Last reviewed June 2026, checked against PrestaShop 1.7, 8.x and 9.x. The Webservice request shown below was verified against a live PrestaShop install.
We build ERP integrations for a living (warehouse sync for wetroomsdesign, stock-and-price feeds for modernedusche, marketplace bridges for several others) and the line we hear most often at the start of a project is "we just need to sync products and orders." Six weeks later it's reconciliation jobs, conflict rules, retry queues and a Slack channel called #stock-mismatches. This page is the shape of what actually works, separate from the API mechanics, we cover those in our Webservice API guide.
Choose Your Sync Direction
The single decision that determines whether the integration is calm or chaotic: who owns each piece of data. Decide this before you write code, not after the ERP and PrestaShop start disagreeing in production.
- ERP → PrestaShop: products, prices, stock, categories. The ERP is the source of truth for anything the warehouse touches.
- PrestaShop → ERP: orders, customers, returns. The shop is where this data is born.
- Bidirectional on the same field: avoid unless you have to. Every project we've seen do this on prices ended up writing a conflict-resolution policy nobody trusts.
The pattern that works: ERP owns the catalogue, PrestaShop owns the orders. The ERP pushes catalogue changes in, the shop pushes completed orders out. A clean checkout matters here too, incomplete or malformed orders pollute the ERP and somebody has to clean them up by hand.
Where the data actually lives: the Webservice

Whichever sync strategy you land on below, the read/write surface is almost always PrestaShop's built-in Webservice. A REST-like HTTP API you turn on under Advanced Parameters → Webservice, generate a key for, and grant per-resource permissions to (tick only what the integration touches). Authentication is HTTP Basic: the key is the username, the password is left blank, always over HTTPS.
A scheduled "pull orders changed since last run", the core of the batch pattern below, is a single GET. This request returns the full order objects placed after a given timestamp, newest first:
GET https://yourstore.com/api/orders?display=full&output_format=JSON&sort=[date_upd_DESC]&filter[date_upd]=[2026-06-01 00:00:00,2026-06-25 23:59:59]&date=1
# Auth: HTTP Basic – username = your Webservice key, password = blank
# curl form:
curl -u "YOUR_WEBSERVICE_KEY:" \
"https://yourstore.com/api/orders?display=full&output_format=JSON&sort=[date_upd_DESC]&filter[date_upd]=[2026-06-01%2000:00:00,2026-06-25%2023:59:59]&date=1"
Two parameters do the heavy lifting: display=full returns the order fields rather than a bare list of IDs, and date=1 is what makes the filter[date_upd] range apply to date columns at all (omit it and the date filter is silently ignored). Default output is XML; output_format=JSON works on versions that support it. Confirm yours does before relying on it. Store the highest date_upd you've seen and use it as the lower bound next run; that "since last run" cursor is the whole game.
Sync Strategies
1. Batch Sync (Scheduled)
A cron job every N minutes, pulling rows changed since the last run (the GET above). Boring, predictable, easy to debug when it breaks at 03:00. This is what we reach for first on roughly 80% of integrations.
- Pros: simple, retries are free, failures are visible the next morning not in the next millisecond
- Cons: stock is stale between runs, for a slow shop, fine; for flash sales, not
- Best for: shops under ~50,000 SKUs and normal order volume. Most of our clients.
2. Event-Driven (Webhooks)
Stock changes fire a webhook. The receiving system processes it from a queue (Redis, RabbitMQ, we use Redis Streams in most builds). Near real-time, but you've now got a queue, a worker, a dead-letter store, and a retry policy to babysit. Note that core PrestaShop has no outbound webhook sender. The event has to be fired from a module bound to the relevant hook (actionValidateOrder for a new order, actionUpdateQuantity for stock movement).
- Pros: near-real-time consistency, no needless polling
- Cons: queue infrastructure, more moving parts, error handling becomes its own product
- Best for: high-volume shops, fast-moving stock, omnichannel where in-store POS can sell something between two PrestaShop cron runs
3. Middleware Layer
An intermediate service does the transformation, MuleSoft, n8n, or something custom. Useful when the ERP also feeds an accounting system, a PIM, and a marketplace; less useful when it's just one shop talking to one ERP.
- Pros: systems stay decoupled, mapping logic lives in one place
- Cons: one more thing that can go down and take the sync with it
- Best for: multi-system landscapes where PrestaShop is one of several consumers
Critical Design Decisions
Use External IDs
Store the ERP's reference alongside PrestaShop's id_product. We typically add an erp_reference column or use the existing reference / EAN field if it's already maintained. Matching by name is how you end up with two products called "Black T-Shirt" merged into one. Matching by SKU alone fails the day someone tidies the SKUs.
Implement Idempotency
Every sync operation must be safe to repeat. If your worker re-processes the same order an hour later, nothing should double-decrement. We use a sync_log table with a unique key on (resource, external_id, operation), the second attempt becomes a no-op and we sleep at night.
Log Everything
One row per sync attempt: what, which direction, success or failure, payload hash, timestamp. The first time the warehouse rings you saying "you sent us the wrong stock", this table is the only thing that tells you whether they're right. If you're cleaning up test orders before going live, our order-cleanup tool is built for exactly that. Keep the sync log though, it's evidence.
Stock Sync: The Hard Problem
This is where every ERP integration project earns its budget. Oversell once on a flash sale and the support cost dwarfs whatever the integration saved. The pattern we use on every build:
- ERP pushes a full stock snapshot at a calm interval, every 5–15 minutes, matched to how fast stock moves.
- PrestaShop decrements stock locally the instant an order is placed. Don't wait for the next ERP poll.
- A nightly reconciliation job compares the two and reports drift. It does not auto-correct. Auto-correct is how you turn a small bug into a catalogue-wide stock reset.
- Drift over a threshold pings somebody. A human decides whether the ERP or PrestaShop is right.
The thing we tell every client at the start of these projects: an ERP integration isn't a project, it's a thing you operate. Build the monitoring, the alerts, the "re-run last night's sync" button, and the dashboard from day one. Modules like Performance Revolution help track shop-side health, and the same instinct applies to the integration itself. The teams that treat the integration as live infrastructure stay calm. The ones that treat it as a finished deliverable get woken up at weekends.
One operational detail people skip: what runs the cron? A scheduled pull is only as reliable as the scheduler firing it. If you don't want sync jobs riding on a fragile server crontab or PrestaShop's default cron URL, our Cron Manager gives every scheduled task a record, a last-run timestamp and a failure you can actually see. Which is precisely the kind of visibility a "thing you operate" needs.
Frequently asked questions
Does PrestaShop have a built-in API I can point my ERP at?
Yes, the Webservice under Advanced Parameters → Webservice. It's a key-based REST-like HTTP API that exposes orders, products, stock, customers, addresses and more. There's no separate "ERP connector" in core; your ERP (or a middleware layer between them) talks to this Webservice directly, or to a connector module that wraps it.
How often should the sync run?
Match the interval to how fast the data moves. Catalogue and price changes are usually fine on a 15-minute or hourly batch. Stock for fast-moving lines is the exception, if overselling is a real risk you decrement locally at order time and treat the ERP poll (every 5–15 minutes) as a correction layer, not the live truth.
What stops the integration double-processing the same order?
An idempotency key, almost always the PrestaShop order or invoice ID, recorded in a sync log with a unique constraint. A retry after a timeout then becomes a no-op instead of a second invoice or a double stock decrement. Build this before go-live, not after the first duplicate.
Should I let the ERP and PrestaShop both edit prices?
No. Pick one owner per field. Two-way sync on the same field (prices especially) forces a conflict-resolution policy that's brittle and hard to trust. The reliable pattern is one source of truth per data type: catalogue and stock from the ERP, orders and returns from PrestaShop.
Do I need real-time webhooks, or is a scheduled pull enough?
For most stores a scheduled pull is enough and far easier to operate. Reach for webhooks only when latency is the whole point. Omnichannel stock where a POS sale can collide with a web sale between polls, or alerts that must fire instantly. Webhooks buy you speed at the cost of a queue, a worker and a retry policy you now have to maintain.
Related reading
- When your store outgrows manual work. The "do I even need this yet" decision, with a way to put a number on it
- Connecting PrestaShop to your accounting software, the ledger half of the same problem (invoices, tax, refunds)
- Zapier and Make for PrestaShop, the lighter-weight glue for the one-off connections that aren't worth a full integration
- PrestaShop Webservice API, the request mechanics behind everything on this page
- PrestaShop Hooks & Overrides. For the event-driven side, the webhook pattern lives here
- Checkout Revolution, clean order data going into your ERP, every time
- Performance Revolution. Keeping the shop responsive while the sync runs
Comments
Leave a comment
Share a question, an installation detail, or feedback that could help another reader.