Guide · PrestaShop

Track PrestaShop Sales Channel by Channel

A PrestaShop store knows everything about its orders and nothing about their origin. The good news: the hook that announces a payment has always been there. The less good news: nobody calls it for you.

Two possible routes — and no third option

The web service

  • An API you query, never one that notifies
  • No native webhooks in PrestaShop
  • Middleware comes and reads the orders
  • Nothing to develop on the store
  • But a lag: you read every x minutes

A small module

  • The actionOrderStatusPostUpdate hook
  • The call fires the moment the status changes
  • The authorization header is set by your code
  • Order reference serves as the idempotency key
  • And the click ID can travel with it

PrestaShop has no checkbox to call an address: the official documentation points to PHP in a module for any outgoing call. That's not a Subtraq limitation, it's how PrestaShop is built — and it fits in one hook and one HTTP call.

The seven module steps

What to know before you search

What the web service does, and what it will never do

Practical consequence: without a module, the only path is having middleware ask the store what is new, at regular intervals. That works, and it's even comfortable — but sales arrive with a lag, and the middleware needs to remember what it's already sent.

The invoice ID saves you there too: if middleware reads the same order twice, the reference is the same and Subtraq doesn't count twice. Re-reading the entire history doesn't create false numbers.

Sources: the web service and external service calls, PrestaShop documentation.

Have n8n read the store

Recorded September 12, 2026

An API that responds, not one that calls

The PrestaShop documentation describes its web service as a CRUD API: it lets a third-party tool access store data. It notifies nothing. For outgoing calls to an external service, the documentation points to developing a module.

The module route, 7 steps

From the status change to the attributed sale

Nothing to install from a marketplace, nothing to buy: a folder, a class, a hook. The module does one thing, and it comes out as fast as it went in.

1

In Subtraq, create a server key

Settings → API Keys. It starts with stq_sk_, carries the events:write permission, and is shown only once. Also note the client workspace slug.

2

Create a minimal module

A PrestaShop module is not an application: it's a folder, a class, and an install method that registers the hook. Yours will have a single responsibility, which makes it easy to review and remove.

3

Register the actionOrderStatusPostUpdate hook

It is called after an order status change and receives the new status, the old status, and the order ID. This is the right place: it fires after the fact, on a done deal, not on an intent.

4

React only to statuses that mean money

Test the new status against its payment flag rather than its label: a label can be translated and renamed in the back office, a flag cannot. Without this test, every move to "in preparation" would send a sale.

5

Build the body and make the call

Five fields: space, amount in cents, currency, invoiceId, email. The total paid and the billing email are read from the order object and its customer. The Authorization header takes Bearer followed by the key.

6

Multiply by one hundred, and round explicitly

Subtraq counts in cents and rejects decimals. A total of $43.90 must leave as 4390: an explicit round prevents PHP floats from turning it into 4389.

7

Put the order reference in invoiceId

It is stable and unique. An order whose status goes back and forth sends the same reference: Subtraq recognizes the duplicate, responds 200, and adds nothing. It's the only protection against inflated revenue.

Hook name and parameters recorded in the PrestaShop documentation on September 12, 2026 — actionOrderStatusPostUpdate and the full list of hooks. Versions change: if what you see no longer matches, the source is authoritative.

The tricky part

Getting the click to the order

In a PrestaShop store, the journey means holding that value between the visitor's arrival and their order confirmation. That's the module's job, and it's what makes attribution exact rather than probable.

Without that, the path is still the customer's email address: Subtraq looks up the person within the workspace attribution window, thirty days by default. That's exactly what the Stripe integration already does, and it's enough in the vast majority of cases.

A note on UTMs: they tell your audience analytics tool about the campaign; they don't link an order to a click. The two mechanisms coexist without replacing each other.

What attribution means

What Subtraq passes to the destination

A parameter named st_id

A Subtraq link adds a st_id parameter to its destination, in the form clk_ followed by twenty-four characters from an unambiguous alphabet. That's the parameter the clickId field in the request expects.

Tricky cases, handled honestly

A store has carts that don't convert, checks that arrive late, statuses that get renamed.

What about abandoned carts?

An abandoned cart is neither a lead nor a sale: recording it as such would corrupt precisely the number your work is judged on. If you want to measure order starts, send a custom event — no amount, from the browser, with a name like 'order_started'. The report will count them separately, in their right place.

A customer pays by bank transfer, two weeks later.

The hook fires on the status change, so the day you mark the order paid. What becomes critical is the attribution window: a click older than it no longer attaches. On a store with slow payments, extend it before connecting — it won't backfill the past.

We've renamed our order statuses.

That's why the test is on the payment flag of the status, not its label. A label can be translated, renamed, duplicated; a status marked as paid stays marked as paid. A module comparing strings would break on the first rename, silently.

A refund, or a cancelled order?

Subtraq doesn't accept negative amounts and has no call to cancel a recorded sale. A cancelled order is simply not sent; a refund is traced with a zero-amount event and corrected manually in the report. It's a limitation, and it's stated.

Frequently asked questions

Is a paid marketplace module needed?

No, and there isn't one from us. The module this page describes is yours: a folder, a class, a hook. If you'd rather not develop anything, the middleware route reads the store through its web service.

Do I need to modify the store theme?

Not for sales: it's server talking to server. Yes, slightly, if you want to carry the click ID from the visitor's arrival to their order.

Is the web service really enough, without a module?

Yes, with a lag and one condition: the middleware must track what it has already sent. The order reference in the invoice ID field protects you from duplicates regardless.

Is a pixel needed on the store?

No. Nothing is added to page rendering to record a sale. The page pixel is only for leads and events, and it never accepts an amount.

Where should the server key be stored?

In the module's configuration or a server environment variable, never in a theme file. It must never reach a browser.

Do your payments go through Stripe?

Then the shortest path doesn't go through PrestaShop: the Stripe integration records every payment on its own, with mandatory signature and nothing to develop.

The Stripe guide

Know which channel sold what, at last

Create an account, grab a server key, hook up the hook. The store answers the question it never knew to ask.

Create a free account