Skip to main content
RapidDev - Software Development Agency
v0-integrationsNext.js API Route

How to Integrate PrestaShop with V0

To build a headless storefront with PrestaShop and V0 by Vercel, enable PrestaShop's Web Services API on your PrestaShop installation, create a Next.js API route that fetches products and categories via REST, and generate the storefront UI with V0. Store your PrestaShop API key in Vercel environment variables. This pattern gives PrestaShop store owners a modern, fast Next.js frontend while keeping their existing PrestaShop backend for inventory and order management.

What you'll learn

  • How to generate a modern e-commerce storefront UI using V0 prompts
  • How to enable and configure PrestaShop's Web Services API
  • How to create a Next.js API route that fetches products and categories from PrestaShop
  • How to display product data including images, prices, and stock levels from PrestaShop
  • How to implement product search and category filtering in a headless PrestaShop storefront
Book a free consultation
4.9Clutch rating
600+Happy partners
17+Countries served
190+Team members
Intermediate14 min read60 minutesE-commerceMarch 2026RapidDev Engineering Team
TL;DR

To build a headless storefront with PrestaShop and V0 by Vercel, enable PrestaShop's Web Services API on your PrestaShop installation, create a Next.js API route that fetches products and categories via REST, and generate the storefront UI with V0. Store your PrestaShop API key in Vercel environment variables. This pattern gives PrestaShop store owners a modern, fast Next.js frontend while keeping their existing PrestaShop backend for inventory and order management.

Build a Modern Headless Storefront on Top of PrestaShop with V0

PrestaShop powers over 300,000 online stores worldwide with its free, open-source e-commerce platform. However, PrestaShop's default theme can feel dated, and achieving a truly modern shopping experience often requires significant theme customization. The headless approach — using PrestaShop purely as the backend (inventory, pricing, orders) while V0 generates a modern Next.js frontend — gives store owners the best of both worlds.

PrestaShop's built-in Web Services API provides RESTful access to all store data: products, categories, customers, orders, inventory, prices, and more. The API returns XML by default but also supports JSON format with the `output_format=JSON` parameter. Authentication uses HTTP Basic auth with a key you generate in the PrestaShop admin panel.

The headless pattern is particularly powerful for stores that have outgrown PrestaShop's template system. Your V0-generated Next.js storefront can be as visually unique as any design, deployable to Vercel's global CDN for fast page loads anywhere in the world, while PrestaShop continues handling the business logic — pricing rules, promotions, tax calculations, shipping rates, and order fulfillment — that would be complex to rebuild.

Integration method

Next.js API Route

PrestaShop integrates with V0 apps through Next.js API routes that call PrestaShop's built-in Web Services REST API. The Web Services API uses HTTP Basic auth with an API key generated in the PrestaShop admin panel. Your API route fetches products, categories, prices, and inventory from PrestaShop and returns normalized data to the V0-generated storefront. The checkout process typically redirects users to PrestaShop's native checkout or uses a separate payment gateway.

Prerequisites

  • A running PrestaShop installation version 1.7 or later (self-hosted or cloud)
  • Admin access to your PrestaShop back office to enable Web Services and generate an API key
  • Your PrestaShop store URL (e.g., https://your-store.com)
  • A V0 project exported to GitHub and deployed on Vercel
  • Basic understanding of Next.js API routes and REST APIs

Step-by-step guide

1

Enable PrestaShop Web Services and Generate an API Key

Log into your PrestaShop back office (usually at your-store.com/admin). Navigate to Advanced Parameters → Webservice. At the top of the page, toggle 'Enable PrestaShop Webservice' to 'Yes' and click 'Save'. Next, click 'Add new webservice key' (the plus button). PrestaShop will generate an API key for you — or you can click 'Generate' to create a new one. Copy this key immediately as you'll add it to Vercel environment variables. For the key permissions, select the appropriate resources. For a read-only storefront, enable GET permission on: `products`, `categories`, `product_features`, `product_feature_values`, `combinations`, `images`, `stock_availables`, `taxes`, `tax_rule_groups`. If you want to handle order creation from the headless frontend, also enable POST/PUT on `carts`, `orders`, and `customers`. Save the webservice key. To verify it works, open your browser and navigate to `https://your-store.com/api/?ws_key=YOUR_API_KEY&output_format=JSON` — you should see a JSON response listing all available API endpoints. If you get a 404, ensure the webservice is enabled. If you get a 403, check the key permissions. PrestaShop's Web Services API base URL is `https://your-store.com/api/` and all endpoints are appended directly: `/api/products`, `/api/categories`, etc. The `output_format=JSON` parameter is required to get JSON instead of XML — always include it.

V0 Prompt

Create a product grid page for an e-commerce store. Show a responsive grid of product cards with product image, product name, current price in bold, 'on sale' badge if there's a discount, and an 'Add to Cart' button. Add a sticky top navigation with category links and a search input. Show loading skeletons while products are fetched.

Paste this in V0 chat

Pro tip: PrestaShop's API key is shown only once when first created. If you lose it, you'll need to generate a new one in Advanced Parameters → Webservice → your key → Edit.

Expected result: PrestaShop Web Services enabled with an API key that has GET permissions on products and categories. Browser test at your-store.com/api/?ws_key=KEY&output_format=JSON returns valid JSON.

2

Create the PrestaShop API Route

Create a Next.js API route at `app/api/prestashop/route.ts` that proxies requests to your PrestaShop Web Services API. PrestaShop uses HTTP Basic authentication where the API key is the username and the password is empty — encode `{API_KEY}:` in Base64 for the Authorization header. PrestaShop's JSON API responses nest data under a key matching the resource name. For example, `GET /api/products?output_format=JSON` returns `{ products: [{ id: 1, ... }] }`. For a single product, `GET /api/products/1?output_format=JSON` returns `{ product: { id: 1, ... } }`. Product data in PrestaShop is structured differently from modern e-commerce APIs. Key fields: `id` (integer), `name` (array keyed by language ID), `description` (multilingual), `price` (tax-excluded, as decimal string), `quantity` (from stock_availables link), `active` (1 or 0). Product images require separate requests to `/api/images/products/{product_id}/{image_id}`. For the storefront, the most efficient approach is to fetch products with `display=[id,name,price,description_short,active]` to limit which fields are returned (reduces payload from ~100 fields to just what you need). Use `filter[active]=1` to only return published products. Use `limit=12&page=1` for pagination. PrestaShop stores multilingual content as arrays: `name: [{ id: '1', language: { id: '1' }, value: 'Product Name' }]`. Extract the display name by finding the entry for your target language ID (usually 1 for English) using `name.find(n => n.language.id === '1')?.value`.

app/api/prestashop/route.ts
1// app/api/prestashop/route.ts
2import { NextRequest, NextResponse } from 'next/server';
3
4const PS_URL = process.env.PRESTASHOP_URL!; // e.g., https://your-store.com
5const PS_KEY = process.env.PRESTASHOP_API_KEY!;
6const LANG_ID = process.env.PRESTASHOP_LANG_ID || '1'; // default language
7
8function getAuthHeader() {
9 return 'Basic ' + Buffer.from(`${PS_KEY}:`).toString('base64');
10}
11
12function extractLangValue(field: any, langId = LANG_ID): string {
13 if (typeof field === 'string') return field;
14 if (!Array.isArray(field)) return '';
15 return field.find((f: any) => String(f?.language?.id ?? f?.attrs?.id) === langId)?.value || '';
16}
17
18async function prestashopFetch(endpoint: string, params?: Record<string, string>) {
19 const url = new URL(`${PS_URL}/api${endpoint}`);
20 url.searchParams.set('output_format', 'JSON');
21 if (params) Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
22
23 const res = await fetch(url.toString(), {
24 headers: { Authorization: getAuthHeader() },
25 next: { revalidate: 300 },
26 });
27 if (!res.ok) throw new Error(`PrestaShop API error: ${res.status}`);
28 return res.json();
29}
30
31export async function GET(request: NextRequest) {
32 const { searchParams } = new URL(request.url);
33 const resource = searchParams.get('resource') || 'products';
34 const id = searchParams.get('id') || '';
35 const page = searchParams.get('page') || '1';
36 const categoryId = searchParams.get('categoryId') || '';
37
38 try {
39 if (resource === 'products') {
40 const params: Record<string, string> = {
41 'display': '[id,name,description_short,price,id_category_default,active]',
42 'filter[active]': '1',
43 'limit': `12,${(parseInt(page) - 1) * 12}`,
44 };
45 if (categoryId) params['filter[id_category_default]'] = categoryId;
46
47 const data = await prestashopFetch('/products', params);
48 const products = (data.products || []).map((p: any) => ({
49 id: p.id,
50 name: extractLangValue(p.name),
51 shortDescription: extractLangValue(p.description_short),
52 price: parseFloat(p.price).toFixed(2),
53 imageUrl: `${PS_URL}/api/images/products/${p.id}/1?ws_key=${PS_KEY}`,
54 categoryId: p.id_category_default,
55 }));
56 return NextResponse.json({ products });
57 }
58
59 if (resource === 'product' && id) {
60 const data = await prestashopFetch(`/products/${id}`, {
61 display: 'full',
62 });
63 const p = data.product;
64 return NextResponse.json({
65 id: p.id,
66 name: extractLangValue(p.name),
67 description: extractLangValue(p.description),
68 price: parseFloat(p.price).toFixed(2),
69 reference: p.reference,
70 weight: p.weight,
71 });
72 }
73
74 if (resource === 'categories') {
75 const data = await prestashopFetch('/categories', {
76 display: '[id,name,active,id_parent]',
77 'filter[active]': '1',
78 });
79 const categories = (data.categories || []).map((c: any) => ({
80 id: c.id,
81 name: extractLangValue(c.name),
82 parentId: c.id_parent,
83 }));
84 return NextResponse.json({ categories });
85 }
86
87 return NextResponse.json({ error: 'Invalid resource' }, { status: 400 });
88 } catch (err: any) {
89 return NextResponse.json({ error: err.message }, { status: 500 });
90 }
91}

Pro tip: PrestaShop product images are served directly from the PrestaShop API URL. For better performance, consider using Next.js Image with the PrestaShop URL added to remotePatterns in next.config.js, or sync images to Vercel Blob storage.

Expected result: The API route returns normalized product and category data from PrestaShop with correct multilingual name extraction and image URLs.

3

Add Vercel Environment Variables

Navigate to your Vercel project → Settings → Environment Variables. Add the required variables for your PrestaShop connection. Add `PRESTASHOP_URL` — the base URL of your PrestaShop store, without a trailing slash (e.g., `https://your-store.com`). This is the URL customers use to access your store. If your store is on a subdomain like `shop.yourcompany.com`, use that URL. Add `PRESTASHOP_API_KEY` — the API key you generated in PrestaShop's Advanced Parameters → Webservice section. This is a 32-character alphanumeric string. Set it without the `NEXT_PUBLIC_` prefix as it must remain server-side only. Optionally add `PRESTASHOP_LANG_ID` — the language ID for your default display language. In PrestaShop, go to International → Languages to see your language IDs. English is typically ID 1. If your store is multilingual or a non-English store, set this to the correct language ID for your primary display language. For staging and testing, if you have a PrestaShop development or staging environment, create separate environment variables for Vercel's Preview deployments pointing to the staging PrestaShop instance. This prevents test orders and test product changes from appearing in production. After saving, redeploy and test the integration by visiting `/api/prestashop?resource=products` in your browser — you should see your actual PrestaShop products in the JSON response.

Pro tip: PrestaShop API keys are sensitive — they can read all order and customer data if given full permissions. Create a separate API key with read-only permissions for the storefront frontend, and a different key with write permissions only if you need to create orders from the headless frontend.

Expected result: PRESTASHOP_URL, PRESTASHOP_API_KEY, and PRESTASHOP_LANG_ID set in Vercel environment variables. Test API call returns product data.

4

Build the Storefront Product Pages

Connect the V0-generated storefront components to your PrestaShop API routes. Create the product listing page using React Server Components for initial data fetching (giving you fast server-rendered page loads) and client components for interactive features like cart state and variant selection. For the product grid, use `generateStaticParams` in Next.js to pre-render category pages at build time — fetch the category list and return each category ID as a static param. This gives fast initial page loads from Vercel's CDN without a server request for the most common browsing patterns. For product images, PrestaShop serves images directly from its Web Services API at `{PS_URL}/api/images/products/{product_id}/{image_id}?ws_key={PS_KEY}`. Since the API key is in the URL (not in a header), these image URLs are technically exposed to the client. For production, consider setting up image proxying through your Next.js API route to keep the key server-side, or use a read-only API key with image-only access. For the checkout flow, redirect users to your PrestaShop store's native cart page after adding items. Alternatively, build cart state in your Next.js app and use PrestaShop's API to create a cart (`POST /api/carts`) and then redirect to PrestaShop's checkout. The fully headless checkout (handling payment entirely in your Next.js app) requires additional complexity: integrating a payment provider and using PrestaShop's order creation API. For product search, PrestaShop's API supports search with `filter[name]=%[search_term]%` but this is case-sensitive. For better search, consider fetching all products and implementing client-side fuzzy search with a library like Fuse.js, or use PrestaShop's search module if installed.

V0 Prompt

Connect the product grid to /api/prestashop?resource=products. Map each product to a card showing the product name, price formatted as currency, and a product image using the imageUrl. When a card is clicked, navigate to /products/[id]. Create the product detail page that fetches /api/prestashop?resource=product&id=[id] and shows the full product description, price, and an 'Order Now' button that links to the PrestaShop product page for checkout. Add category filter buttons that re-fetch products with ?categoryId=X.

Paste this in V0 chat

app/products/page.tsx
1// Example: Product listing page as React Server Component
2// app/products/page.tsx
3import Image from 'next/image';
4
5interface Product {
6 id: number;
7 name: string;
8 shortDescription: string;
9 price: string;
10 imageUrl: string;
11}
12
13async function getProducts(categoryId?: string): Promise<Product[]> {
14 const params = new URLSearchParams({ resource: 'products' });
15 if (categoryId) params.set('categoryId', categoryId);
16 const baseUrl = process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000';
17 const res = await fetch(`${baseUrl}/api/prestashop?${params}`, {
18 next: { revalidate: 300 },
19 });
20 const data = await res.json();
21 return data.products || [];
22}
23
24export default async function ProductsPage({
25 searchParams,
26}: {
27 searchParams: { category?: string };
28}) {
29 const products = await getProducts(searchParams.category);
30
31 return (
32 <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6 p-6">
33 {products.map((product) => (
34 <a key={product.id} href={`/products/${product.id}`}
35 className="group border rounded-xl overflow-hidden hover:shadow-lg transition-shadow">
36 <div className="aspect-square relative bg-gray-100">
37 <img
38 src={product.imageUrl}
39 alt={product.name}
40 className="object-cover w-full h-full group-hover:scale-105 transition-transform"
41 />
42 </div>
43 <div className="p-4">
44 <h3 className="font-semibold text-gray-900">{product.name}</h3>
45 <p className="text-sm text-gray-500 mt-1 line-clamp-2">{product.shortDescription}</p>
46 <p className="text-lg font-bold text-gray-900 mt-2">${product.price}</p>
47 </div>
48 </a>
49 ))}
50 </div>
51 );
52}

Pro tip: PrestaShop's pagination uses offset-based format: `limit=12,0` for the first page (12 items starting at offset 0), `limit=12,12` for the second page. This is different from the more common `page=1&per_page=12` format.

Expected result: The product grid shows real PrestaShop products with images, names, and prices. Category filtering works. Clicking a product navigates to the detail page with full product information.

Common use cases

Modern Product Catalog Frontend

Replace PrestaShop's template with a fast, modern product catalog built with V0. The storefront shows products in a filterable grid, with category navigation, search, and product detail pages — all powered by PrestaShop's product database via API routes.

V0 Prompt

Create an e-commerce product catalog page with a sidebar for category filtering and price range slider, and a main product grid (3 columns) showing: product image, product name, price in bold, original price crossed out if on sale, stock badge ('In Stock' / 'Low Stock' / 'Out of Stock'), and an 'Add to Cart' button. Include a search bar at the top. Show 12 products with pagination.

Copy this prompt to try it in V0

Product Detail Page with Variants

Build a product detail page that shows all product variants (colors, sizes) from PrestaShop, updates the price and availability based on the selected combination, and links to PrestaShop's cart for checkout.

V0 Prompt

Create a product detail page with: large product image gallery with thumbnail strip, product name as h1, current price and sale price, star rating (4.5 stars), variant selector (color swatches and size buttons), quantity selector, 'Add to Cart' button, product description tabs (Description, Specifications, Reviews), and related products row at the bottom.

Copy this prompt to try it in V0

B2B Trade Portal

Build a wholesale portal where registered B2B customers log in to see their negotiated prices, place bulk orders, and track order history — all pulling from PrestaShop's B2B pricing groups and customer accounts via the API.

V0 Prompt

Create a B2B product order form with a searchable product table showing: product reference, name, your price (B2B rate), minimum order quantity, current stock, quantity input field, and 'Add to Order' button. Include an order summary panel on the right showing running total. Add category tabs at the top for quick filtering.

Copy this prompt to try it in V0

Troubleshooting

API returns 404 with 'This method combination is not allowed'

Cause: The Web Services API is not enabled in PrestaShop, or the API key doesn't have permission for the requested resource.

Solution: Go to PrestaShop admin → Advanced Parameters → Webservice and verify the service is enabled. Check that your API key has GET permission for the resource you're requesting. For images, you need GET permission on the 'images' resource specifically.

Product names appear as '[object Object]' or show raw JSON instead of a string

Cause: PrestaShop stores multilingual content as an array of objects. You're rendering the raw array instead of extracting the display string for your language.

Solution: Use the extractLangValue helper function to extract the string value for your target language ID. PrestaShop returns multilingual fields as arrays even for single-language stores.

typescript
1// Correct: extract the string value
2const name = extractLangValue(product.name); // 'Blue Widget'
3// Wrong: renders the raw array
4const name = product.name; // [{language: {id: '1'}, value: 'Blue Widget'}]

Product images return 401 Unauthorized in the browser

Cause: PrestaShop image API URLs require the API key as a query parameter, and the browser is not including it. If you're trying to use the image URL in a Next.js Image component, the key needs to be in the URL.

Solution: Include the API key in image URLs as a query parameter: `${PS_URL}/api/images/products/${id}/1?ws_key=${PS_KEY}`. For production, create an image proxy route that fetches the image server-side and forwards it to the browser, keeping the API key server-side.

typescript
1// Image proxy route: app/api/prestashop/image/route.ts
2export async function GET(request: NextRequest) {
3 const { searchParams } = new URL(request.url);
4 const productId = searchParams.get('productId');
5 const imageId = searchParams.get('imageId') || '1';
6 const imageUrl = `${process.env.PRESTASHOP_URL}/api/images/products/${productId}/${imageId}?ws_key=${process.env.PRESTASHOP_API_KEY}`;
7 const res = await fetch(imageUrl);
8 return new Response(res.body, { headers: { 'Content-Type': res.headers.get('Content-Type') || 'image/jpeg' } });
9}

API returns empty array for products despite products existing in PrestaShop

Cause: The `filter[active]=1` filter or the category filter may be excluding all products, or the API key doesn't have permission to view the products resource.

Solution: Remove the active filter first to see all products regardless of status. Check that products are published (active) in PrestaShop admin. Verify the API key's permissions include GET for the products resource.

typescript
1// Debug: fetch all products without filters
2const data = await prestashopFetch('/products', {
3 display: '[id,name,active]',
4 // Remove filter[active] to see all products including inactive
5});

Best practices

  • Create a read-only API key for the storefront with only the permissions needed — don't use an all-access key in client-facing API routes
  • Cache PrestaShop API responses for at least 5 minutes — product data rarely changes minute to minute and caching dramatically reduces API calls
  • Proxy PrestaShop product images through a Next.js API route to avoid exposing the API key in image URLs
  • Use the display parameter to request only the fields your frontend needs — PrestaShop product objects have 100+ fields and fetching all of them wastes bandwidth
  • Handle PrestaShop's multilingual array format for all text fields — always use an extractLangValue helper function rather than accessing raw array data
  • Pre-render category and product pages with generateStaticParams and Next.js ISR for fast CDN-cached page loads without server requests on every visit
  • Test your integration against PrestaShop's staging environment before pointing it at production — avoid testing API calls against live inventory

Alternatives

Frequently asked questions

Does PrestaShop's Web Services API work with all PrestaShop versions?

The Web Services API has been available since PrestaShop 1.4, but there are differences between versions. PrestaShop 1.7 and 8.x have more complete API coverage and JSON support. If you're on PrestaShop 1.6, the API returns XML by default and some endpoints work differently. The code in this guide targets PrestaShop 1.7+ with JSON output. For PrestaShop 8.x, there's also a newer API available alongside the legacy Web Services API.

Can I handle the full checkout process in my V0 Next.js app?

Yes, but it's complex. You'd need to use PrestaShop's cart API to create and manage cart items, then create an order via the API and handle payment separately with Stripe or another payment provider. For most headless implementations, the simpler approach is managing the cart in your Next.js app's state and redirecting users to PrestaShop's native checkout page when they're ready to pay. This keeps PrestaShop handling tax calculation, shipping rates, and payment — which are complex to replicate.

How do I show product variants (colors, sizes) from PrestaShop?

PrestaShop product combinations are available through the `combinations` resource. Each combination represents a specific variant (e.g., Blue + Large). Fetch combinations with `GET /api/combinations?filter[id_product]={product_id}&display=full&output_format=JSON`. Each combination has `price` (differential price modifier), `quantity`, and references to product attributes. The attributes themselves are in the `product_option_values` resource.

Is the PrestaShop Web Services API rate limited?

PrestaShop's Web Services API doesn't have built-in rate limiting by default — it's constrained by your server's capacity. For self-hosted PrestaShop, the limiting factor is your hosting server's MySQL query performance and PHP processing speed. If you're hitting performance issues, implement aggressive Next.js fetch caching and consider using PrestaShop's built-in cache (APCu or Memcache) on the PHP side to speed up API responses.

Can I use this integration with PrestaShop Cloud?

Yes, PrestaShop Cloud (the hosted SaaS version) includes the Web Services API. Enable it in your PrestaShop Cloud admin panel under Advanced Parameters → Webservice. The API endpoint and authentication work identically to self-hosted PrestaShop. The main difference is you don't control the server, so you cannot install additional modules that might affect API behavior.

RapidDev

Talk to an Expert

Our team has built 600+ apps. Get personalized help with your project.

Book a free consultation

Need help with your project?

Our experts have built 600+ apps and can accelerate your development. Book a free consultation — no strings attached.

Book a free consultation

We put the rapid in RapidDev

Need a dedicated strategic tech and growth partner? Discover what RapidDev can do for your business! Book a call with our team to schedule a free, no-obligation consultation. We'll discuss your project and provide a custom quote at no cost.