# PrestaShop

- Tool: Bubble
- Difficulty: Intermediate
- Time required: 2–3 hours
- Last updated: July 2026

## TL;DR

Connect your Bubble app to PrestaShop using the Webservice API and Bubble's API Connector. The two non-obvious requirements: append output_format=JSON to every call (PrestaShop defaults to XML, which Bubble cannot parse) and add display=full so endpoints return actual data instead of ID-only lists. Authentication is Basic Auth — your API key as username, empty password.

## Why Bubble Founders Integrate with PrestaShop

PrestaShop is a mature open-source platform with powerful back-office tooling, but its admin interface is built for store managers, not for building customer-facing apps or custom B2B portals. Bubble fills that gap. Typical patterns include a Bubble mobile-responsive portal for wholesale customers to browse products and place orders, an internal dashboard for staff to monitor order queues and trigger status changes, and a public-facing product catalog that pulls live inventory from PrestaShop while offering a more polished UI than the default theme.

The PrestaShop Webservice API makes all of this possible. It exposes endpoints for products, orders, customers, categories, stock, and more. The integration is straightforward once you know the two mandatory query parameters — output_format=JSON (PrestaShop defaults to XML) and display=full (without it, list endpoints return only resource IDs, not the actual data). Authentication is unusually simple: Basic Auth with the API key as username and an empty password. Because Bubble's API Connector runs server-side, the key stays private automatically when you check the Private box.

This tutorial walks you through the complete setup: enabling the Webservice, creating a scoped API key, configuring the API Connector, building product and order calls with proper pagination, and updating order status the correct way (via order_histories, not a full PUT on orders). You will also learn how to handle PrestaShop's multi-language field arrays in Bubble's response mapper.

## Before you start

- A live PrestaShop store accessible at a public URL with HTTPS enabled (required for Bubble server-side calls)
- Admin access to the PrestaShop back office (to enable the Webservice and create API keys)
- A Bubble account on any plan (reading data works on Free; Backend Workflow webhooks require a paid plan)
- Bubble's API Connector plugin installed — if it is not already in your Plugins tab, add it from the Bubble plugin marketplace
- The base URL of your PrestaShop store's API: https://your-store.com/api

## Step-by-step guide

### 1. Enable the PrestaShop Webservice and Create an API Key

PrestaShop's Webservice API is disabled by default. Log in to your PrestaShop back office and navigate to Advanced Parameters → Webservice. At the top of the page, set Enable PrestaShop Webservice to Yes and click Save. This activates the /api route on your store.

Next, create an API key scoped to the resources your Bubble app needs. Click Add Webservice Key (or the plus icon). On the key creation screen, click Generate to create a random API key — copy it immediately and store it somewhere safe, because PrestaShop will not show the full key again after you save. Give the key a description like 'Bubble Integration'.

Below the key details, you will see a Permission Matrix listing every PrestaShop resource (orders, products, customers, order_histories, stock_availables, and more). Grant GET permission for all resources your app will read, and also POST for order_histories (needed for status updates). Only give PUT or DELETE permissions if you specifically plan to update or delete resources — the principle of least privilege reduces risk if the key is ever exposed. Click Save when done.

After saving, verify that the Webservice is working by visiting https://your-store.com/api in your browser. If you see an XML index listing the available resources, the Webservice is live. If you get a 404, check that mod_rewrite is enabled on your web server and that the .htaccess file in your PrestaShop root includes the Webservice rewrite rules.

**Expected result:** Visiting https://your-store.com/api in a browser shows an XML index of available resources. You have a Webservice API key copied and ready, with appropriate resource permissions set.

### 2. Install the API Connector Plugin and Configure Base Settings

In your Bubble editor, click the Plugins tab in the left sidebar, then click Add plugins. Search for API Connector and install the API Connector by Bubble. Once installed, click Add another API to create a new connector. Name it PrestaShop.

Set the Authentication dropdown to Basic Auth. In the Username field, paste your PrestaShop Webservice API key. Leave the Password field completely empty — not a space, not a zero, completely empty. Check the Private box on the Username field. This is critical: PrestaShop's Webservice authentication uses the API key as the HTTP Basic Auth username with no password. This is different from every other API you have used, and any character in the password field will cause a 401 error.

Now add two shared URL parameters that must be present on every call. Click Add shared headers or parameters and add:
- Parameter name: output_format | Value: JSON
- Parameter name: display | Value: full

The output_format=JSON parameter tells PrestaShop to respond with JSON instead of its default XML. Without it, Bubble's API Connector cannot parse the response and the Initialize Call will fail with a confusing error. The display=full parameter tells PrestaShop to return complete resource objects rather than a list of IDs — without it, endpoints like GET /products return only a list of ID numbers, and Bubble has nothing to bind.

Set the base URL of the connector to https://your-store.com/api (replace with your actual store domain). Do not include a trailing slash.

```
{
  "connector_name": "PrestaShop",
  "base_url": "https://your-store.com/api",
  "authentication": "Basic Auth",
  "username": "<Your Webservice API Key> [Private]",
  "password": "[empty — leave blank]",
  "shared_url_parameters": [
    { "key": "output_format", "value": "JSON" },
    { "key": "display",       "value": "full" }
  ]
}
```

**Expected result:** The PrestaShop connector appears in your API Connector plugin list with Basic Auth configured, the API key set as username (Private, empty password), and output_format=JSON and display=full set as shared URL parameters.

### 3. Run the Initialize Call and Map the Orders Response

Now add your first API call to verify the connection. Inside the PrestaShop connector, click Add another call. Name it Get Orders. Set the method to GET and the path to /orders. Bubble will append the shared output_format and display parameters automatically. Leave the call parameters empty for now — you will add filtering and pagination in the next step.

Click Initialize call. Bubble will send the actual HTTP request to https://your-store.com/api/orders?output_format=JSON&display=full using your Basic Auth credentials. For the Initialize Call to succeed, your PrestaShop store must have at least one order — if it is a fresh store with zero orders, PrestaShop returns an empty array that Bubble may not map correctly. In that case, create a test order in your PrestaShop back office first.

If the call succeeds, Bubble displays the JSON response and auto-detects the fields. You will see the orders array with fields like id, reference, id_customer, current_state, date_add, total_paid, and nested objects like addresses. Click the field toggle next to each field you want to use in your app to include it in Bubble's response schema.

If the Initialize Call fails: check the Logs tab in Bubble → API Connector logs for the HTTP status. A 200 response with XML content in the body means you forgot the output_format=JSON shared parameter — go back and add it. A 401 means the API key or password is wrong — confirm the key is the username and the password is truly empty.

Set the Use as dropdown to Data so you can use this call as a data source in Repeating Groups and Searches.

```
{
  "call_name": "Get Orders",
  "method": "GET",
  "path": "/orders",
  "effective_url": "https://your-store.com/api/orders?output_format=JSON&display=full",
  "use_as": "Data"
}
```

**Expected result:** Bubble shows the JSON response from your PrestaShop store, auto-detects the orders fields, and marks the call as successfully initialized. The Get Orders call is ready to use as a data source.

### 4. Build the Product Catalog Call with Pagination

Add a second API call named Get Products. Method: GET, path: /products. Because you already set display=full and output_format=JSON as shared parameters, this call inherits them automatically.

PrestaShop supports filtering and pagination via URL parameters. Add the following dynamic parameters to this call:
- limit: with a default value of 20 (you will bind this to a number in your Bubble page)
- limit_offset: with a default value of 0 (for the starting position)

PrestaShop uses an unusual pagination syntax: the limit parameter doubles as the page size when used alone, and becomes limit=[offset],[count] when used with an offset. In Bubble, you cannot easily combine two values into one URL parameter — so use the two separate parameters above and compute the offset in your page using a custom state for the current page number. For example, to show page 2 with 20 products per page, pass limit=20 and add a separate parameter filter[id_category][value] to filter by category.

For category filtering, add an optional parameter named filter[id_category][value] with a default value you can leave empty. PrestaShop's filter syntax for a single value is filter[field][operator]=value — the field name goes in the brackets and the operator (literal string like filter or ilike) is a second bracket segment. For example: /products?filter[id_category_default][value]=3&output_format=JSON&display=full.

For multi-language product names, PrestaShop returns the name field as an array of language objects: [{ "id": "1", "value": "Product Name EN" }, { "id": "2", "value": "Nom du produit FR" }]. In Bubble's response mapper, map name's first item's value (name[0].value in Bubble's dot notation) to get the default language text. Add a shared URL parameter language=1 (or your store's default language ID) to restrict returned translations to one language and simplify the response.

Click Initialize Call after adding a valid category filter or leaving it unfiltered. Bubble will auto-detect fields including id, reference, name, price, id_category_default, active, date_add, and the nested associations for categories and images.

```
{
  "call_name": "Get Products",
  "method": "GET",
  "path": "/products",
  "parameters": [
    { "key": "limit",  "value": "20",  "type": "dynamic" },
    { "key": "limit_offset", "value": "0", "type": "dynamic" },
    { "key": "filter[id_category_default][value]", "value": "", "type": "dynamic" },
    { "key": "language", "value": "1", "type": "static" }
  ],
  "note": "PrestaShop pagination: limit=N returns N items starting at offset 0. To get page 2, pass limit_offset=20 with limit=20."
}
```

**Expected result:** The Get Products call initializes successfully, auto-detecting product fields including id, reference, price, active status, and the multi-language name array. You can now drag this call into a Repeating Group data source with limit and offset parameters bound to page state variables.

### 5. Update Order Status via order_histories (Not PUT /orders)

The most common action in a Bubble order dashboard is advancing an order through fulfillment states — from 'Payment Accepted' to 'Preparing Order' to 'Shipped'. PrestaShop has a dedicated endpoint for this: POST to /api/order_histories. This is preferable to attempting PUT /api/orders for two reasons: the /api/orders PUT endpoint requires you to send the complete order object (fetch, modify, then put the entire thing back), while POST /api/order_histories only needs the order ID and the new state ID. It is also semantically correct — PrestaShop tracks every status change as a history entry, the same way the back office does.

Add a new API call named Update Order Status. Method: POST, path: /order_histories. Set the body type to JSON. In the body field, enter the following structure with dynamic fields for order ID and state ID:

You can find your PrestaShop order state IDs in Orders → Statuses in the back office. Common state IDs on a default installation are: 1=Awaiting check payment, 2=Payment accepted, 3=Preparing order, 4=Shipped, 5=Delivered, 6=Cancelled — but these IDs vary by installation, so always check your own back office.

For the Initialize Call on a POST endpoint, Bubble needs a valid test payload. Enter a real order ID from your store and a valid state ID (e.g., the current state of that order) as the test values. Click Initialize Call — PrestaShop will create an actual order_history entry on your store, so use a test order. If the call succeeds, you will see the created order_history object in the response.

In your Bubble workflows, trigger this call from a button click on your order dashboard. Pass the order ID from the current Repeating Group row and the target state ID from a Dropdown element that lists the available states. Use the 'Use as' setting of Action (not Data) for this call since it performs a write operation.

```
{
  "call_name": "Update Order Status",
  "method": "POST",
  "path": "/order_histories",
  "body_type": "JSON",
  "body": {
    "order_history": {
      "id_order": "<dynamic: order_id>",
      "id_order_state": "<dynamic: new_state_id>",
      "id_employee": "1"
    }
  },
  "note": "Do NOT PUT to /orders — use POST /order_histories. This avoids the full-object requirement and matches how PrestaShop's own admin records status changes."
}
```

**Expected result:** The Update Order Status call is initialized as an Action. When triggered in a Bubble workflow with a real order ID and state ID, PrestaShop creates a new order_history entry, advances the order to the new state, and returns the created object. Customer notification emails are sent if configured in PrestaShop for that state.

### 6. Handle Multi-Language Fields and Display Product Data in Repeating Groups

PrestaShop stores multi-language content (product names, descriptions, meta titles, category names) as arrays of language-keyed objects. A product name in a bilingual store looks like this in the API response: name = [{ "id": "1", "value": "Red Leather Wallet" }, { "id": "2", "value": "Portefeuille en cuir rouge" }]. This array format requires a specific mapping approach in Bubble.

The easiest approach is to pass language=[id] as a URL parameter on your product calls (you added this in Step 4). When you restrict to a single language, PrestaShop still returns the array format but with only one entry, and Bubble's Initialize Call maps it as name with a nested item that has id and value fields. In Bubble's Repeating Group cells, reference the product name as Current Cell's Prestashop Product's name[0]'s value using Bubble's list-item syntax.

For descriptions, PrestaShop returns description and description_short as similarly structured arrays. Map description[0].value for the full HTML description (note: it contains HTML tags — use Bubble's :HTML element or a Rich Text Display element to render it correctly in your UI).

For product images, PrestaShop does not return direct image URLs in the standard API response — it returns associations.images as a list of image ID objects. To display a product image, construct the URL manually using Bubble's text concatenation: https://your-store.com/ + [image_id] + / + [image_id] + -medium_default/ + [product_link_rewrite] + .jpg. Alternatively, add a separate Get Product Images call targeting /images/products/[product_id] to fetch the image list for a specific product.

Bind your Get Products call to a Repeating Group's data source with the limit parameter set to 20 and the limit_offset parameter set to a custom state number named current_offset. Add Previous and Next buttons that subtract and add 20 to the current_offset state to paginate through the catalog. If RapidDev's team has built hundreds of Bubble apps with PrestaShop-style pagination, you know this offset arithmetic is the most common point of confusion — free scoping call at rapidevelopers.com/contact if you want to discuss the right architecture for your specific store size.

```
{
  "repeating_group_data_source": "Get from API PrestaShop / Get Products",
  "parameters": {
    "limit": 20,
    "limit_offset": "CustomState:current_offset"
  },
  "cell_bindings": {
    "product_name": "Current Cell's PS Product's name[0]'s value",
    "product_description": "Current Cell's PS Product's description_short[0]'s value (HTML — use RTE display)",
    "product_price": "Current Cell's PS Product's price",
    "product_id": "Current Cell's PS Product's id"
  },
  "pagination_button_workflows": {
    "next_page": "Set custom state current_offset to current_offset + 20",
    "prev_page": "Set custom state current_offset to max(0, current_offset - 20)"
  }
}
```

**Expected result:** Your Repeating Group displays PrestaShop products with names, prices, and short descriptions. Next/Previous pagination advances through the catalog using the offset parameter. Multi-language name and description fields render correctly using [0].value list notation in Bubble.

## Best practices

- Always set output_format=JSON and display=full as shared connector-level parameters, not per-call parameters. This ensures you never forget them on new calls added later, and avoids the XML parse error on every new endpoint you add.
- Scope your Webservice API key to only the resources and HTTP methods your Bubble app actually needs. A read-only dashboard should have only GET permissions. An order management panel needs GET on orders and POST on order_histories. Avoid granting DELETE unless you have a specific use-case — a mistaken workflow trigger could permanently delete products.
- Always use POST /api/order_histories for order status changes. Never attempt to PUT the full /api/orders resource for a status update — constructing the correct full-object body is error-prone and unnecessary. The order_histories endpoint is the PrestaShop-idiomatic way to advance order status and also triggers the correct customer notification emails.
- Add Privacy Rules to any Bubble Data Things that store PrestaShop data (cached products, orders, customers). Go to Data tab → Privacy and set visibility rules based on user roles. Without privacy rules, Bubble's default data API exposes records to anyone who knows the URL pattern — even if you restrict the Bubble app UI.
- Paginate all list calls with limit and limit_offset. Never fetch the full catalog in a single call with display=full — large catalogs will exceed response size limits or cause Bubble page timeouts. Use 20–50 items per page and drive pagination with a custom state variable tracking the current offset.
- Monitor Workload Units in Bubble's Logs tab. Every API Connector call and workflow run consumes WUs. If your app polls PrestaShop for order updates on a schedule (instead of using webhooks), each poll is a WU charge. Use Backend Workflow webhooks on a paid plan where possible — they are event-driven and only fire when something actually changes, making them far more WU-efficient than polling.
- Test order status changes on a staging PrestaShop installation before using them in production. PrestaShop sends customer emails when order status changes, and there is no way to undo an email once sent. A test order with your own email address is the safest way to confirm the workflow behaves as expected.
- Store your PrestaShop API key in Bubble's API Connector Private field — never in a custom state, URL parameter, or page text element. Private fields are sent from Bubble's servers and are never visible to end users in the browser's network tab or developer tools.

## Use cases

### Custom B2B Ordering Portal

Wholesale customers log in to a Bubble app, browse the PrestaShop product catalog filtered by their account's price tier, add items to a Bubble cart, and submit an order that creates a PrestaShop order via the API. The Bubble portal handles the UX and business rules (minimum quantities, customer-specific pricing) while PrestaShop remains the system of record for inventory, fulfillment, and invoicing.

### Internal Order Management Dashboard

A Bubble admin panel pulls all open orders from PrestaShop, displays them sorted by status and shipping deadline, and lets staff click a button to advance each order through the fulfillment pipeline. Status changes POST to PrestaShop's /api/order_histories endpoint, triggering PrestaShop's native customer notification emails.

### Live Inventory and Product Catalog App

A Bubble-built storefront or mobile app fetches the PrestaShop product catalog in real time, displaying stock levels, prices, and multi-language descriptions. The app is refreshed on a schedule or on user action, giving customers a custom shopping experience without migrating away from PrestaShop's back office.

## Troubleshooting

### API Connector Initialize Call fails with a parse error or shows raw XML instead of JSON fields

Cause: The output_format=JSON shared URL parameter is missing or spelled incorrectly. PrestaShop responds with XML by default, which Bubble's API Connector JSON parser cannot read.

Solution: Go to Plugins → API Connector → your PrestaShop connector → shared parameters. Confirm that output_format is set to JSON (case-sensitive). Add it if it is missing. Re-run Initialize Call. Every call inherits shared parameters, so adding it once to the connector level fixes all calls.

### API calls return 401 Unauthorized even though the API key looks correct

Cause: PrestaShop's Basic Auth convention uses the API key as the username with a completely empty password. If the password field in Bubble's API Connector contains any character — including an accidental space — authentication fails with 401.

Solution: Open the PrestaShop connector in API Connector → Authentication section. Click into the Password field and delete every character, including spaces. Confirm the Username field contains only the API key (no extra spaces before or after). Save and re-run Initialize Call.

### List endpoints (GET /products, GET /orders) return only a list of ID numbers, not actual product or order data

Cause: The display=full shared URL parameter is missing. Without it, PrestaShop list endpoints return an index of resource IDs only, not the full resource objects.

Solution: Add display=full as a shared URL parameter on the connector (same place as output_format=JSON). Shared parameters apply to all calls automatically. Re-initialize the affected call after adding the parameter — the detected fields will change from a single id list to the full resource schema.

### Bubble times out or returns an empty response when calling GET /products with display=full on a large catalog

Cause: display=full on a large product catalog returns a very large JSON payload (potentially several megabytes), which can exceed Bubble's response timeout or Bubble's API response size limits.

Solution: Always combine display=full with a limit parameter to paginate the response. Add limit=20 (or similar) as a parameter on the Get Products call. Bubble's API Connector has a practical limit on response payload — do not fetch more than 50-100 products at a time. Use the limit_offset pattern to page through the catalog incrementally rather than loading everything at once.

```
{
  "path": "/products",
  "parameters": [
    { "key": "display",       "value": "full" },
    { "key": "output_format", "value": "JSON" },
    { "key": "limit",         "value": "20" },
    { "key": "limit_offset",  "value": "0" }
  ]
}
```

### POST to /order_histories returns 400 Bad Request or a PrestaShop webservice error

Cause: The request body format is incorrect. Common mistakes: sending the order_history object at the top level without the wrapper key, or using a string where PrestaShop expects a number for id_order or id_order_state.

Solution: Confirm the body exactly matches the required structure with the order_history wrapper key. Both id_order and id_order_state must be integers, not strings — in Bubble, use Convert text to number if you are passing these as dynamic text values from your app. Also confirm that the order ID exists in your store and that the target order state ID exists in PrestaShop's order state list.

```
{
  "order_history": {
    "id_order": 42,
    "id_order_state": 4,
    "id_employee": 1
  }
}
```

## Frequently asked questions

### Do I need a paid Bubble plan to connect to PrestaShop?

No — reading data from PrestaShop (GET calls for products, orders, customers) works on Bubble's Free plan using the API Connector. You only need a paid Bubble plan if you want to receive inbound webhooks from PrestaShop via Backend Workflows, or if you want to schedule recurring API calls using Bubble's Schedule API Workflow feature. Basic outbound API calls to PrestaShop work on all Bubble plans.

### Why does my API Connector Initialize Call return XML instead of JSON?

PrestaShop defaults to XML output for all Webservice responses. You must include output_format=JSON as a URL parameter on every call. The easiest way to ensure this is to add it as a shared parameter on the connector level in Bubble's API Connector, so it is automatically included in all calls you create under that connector.

### What is the correct way to change an order's status from Bubble?

POST to /api/order_histories with the order ID and the target state ID. Do not attempt to PUT the full /api/orders resource — PrestaShop's PUT endpoints require the complete resource object, which is complex to construct correctly for orders. The order_histories endpoint is simpler, PrestaShop-idiomatic, and also triggers the correct customer notification emails defined in your order state settings.

### How do I display product names when PrestaShop returns them as a language array?

PrestaShop multi-language fields like name and description are returned as arrays of { id, value } objects, one entry per configured language. In Bubble's response mapper, reference name[0].value to get the first language entry. To simplify this, add language=[your_default_language_id] as a URL parameter on product calls — PrestaShop will still return an array but with only the requested language, making the [0].value mapping consistent.

### Can I use PrestaShop webhooks to receive real-time order updates in Bubble?

Yes, but it requires a paid Bubble plan. Create a Bubble Backend Workflow (Settings → API → enable Workflow API → Backend Workflows → new API Workflow) and use Detect Request Data to parse the incoming PrestaShop webhook payload. Then register the Bubble endpoint URL in PrestaShop's webhook module. Without a paid plan, you must poll the /orders endpoint on a schedule instead, which consumes Workload Units and has inherent delay.

### Why do I get empty results when calling GET /products even though my store has products?

The most common cause is a missing display=full parameter. Without it, PrestaShop returns only a list of product IDs, not the product data. Add display=full as a shared connector parameter. The second common cause is the output_format parameter being absent, causing an XML response that Bubble cannot parse. Confirm both parameters are set and re-initialize the call.

---

Source: https://www.rapidevelopers.com/bubble-integrations/prestashop
© RapidDev — https://www.rapidevelopers.com/bubble-integrations/prestashop
