Guide · Shopify
Track Shopify sales without a pixel
Your store knows what it sold. It doesn't know which story, email, or post sold it. One paid order, one request, and the answer is in the report.
The whole guide fits right here
Shopify
Flow → Order paid → Send HTTP request
Subtraq
Settings → API Keys → events:write
The address is Subtraq's: you paste it into the Send HTTP request action in Flow, with the server key in a header. From there, every paid order becomes a sale credited to the link that drove it — no pixel, no line added to the theme.
Read this before looking in your settings
Shopify's native webhooks won't work — here's why
Subtraq requires a server key in an Authorization header. Without it, anyone could write revenue into a client's report: the key is not a formality, it's what makes the number defensible.
The conclusion, and there's no way around it: the Settings → Notifications → Webhooks → Create webhook path cannot reach Subtraq. You need an action that can set a header. Flow is one. Zapier, Make, and n8n are others.
Source: accepted fields when creating a webhook and delivery structure, Shopify documentation.
What a Shopify webhook can do, and can't do
Creating a webhook subscription accepts a URL, a filter, and a list of fields to include. It accepts no custom header. Shopify signs its deliveries with the X-Shopify-Hmac-Sha256 header, and that is the only sender proof it sets.
In Shopify Flow, 6 steps
From server key to first recorded order
Shopify Flow is available on the Shopify Plus, Advanced, and Grow plans, according to its reference page. On a lower plan, skip to the last section of this page: Zapier, Make, and n8n do the same job from the outside.
In Subtraq, create a server key
Settings → API Keys. The key starts with stq_sk_ and must carry the events:write permission. It is shown only once. Also note the client workspace slug: it's the one that appears in the address bar of its dashboard.
In Shopify, open Flow and create a workflow
The trigger to choose is "Order paid". This is the Flow equivalent of the orders/paid webhook topic: the order is paid, so there's a number to record.
Store the key in a secret
Flow lets you store a sensitive value and call it later in Liquid as {{secrets.handle}}. The server key should never be copied in plain text into a field that other store administrators can read.
Add the "Send HTTP request" action
Method POST, URL https://subtraq.co/api/v1/sales. In the Headers field, add Authorization with the value Bearer followed by the secret, then Content-Type with application/json.
Write the request body
Five fields are enough: space, amount in cents, currency, invoiceId, email. Shopify expresses the amount in the main unit ("43.00"): Flow must multiply by one hundred, because Subtraq rejects decimal numbers for money.
Trigger a test order and read the response
Subtraq responds 201 for a new sale, 200 if the same invoiceId has already come through. The response carries attributed: true if the sale found its original link, false if Subtraq found nothing — and it says so rather than inventing something.
Paths recorded in the Shopify documentation on September 12, 2026 — the Send HTTP request action and the list of webhook topics. Interfaces change: if what you see no longer matches, the source is authoritative.
The request body
Five fields, and two traps that cost you
First trap: the amount. Subtraq works in cents and rejects decimals: $43 is written as 4300. Shopify exposes the total in the main unit. One forgotten multiplication divides your client's revenue by one hundred, and nobody catches it right away.
Second trap: the invoice ID. That's what prevents double-counting. Shopify retries its deliveries, and Flow can fire twice on the same order: put the order number in invoiceId and the second pass responds 200 without adding anything.
The fields, as the code reads them
space (the workspace slug) · amount (an integer, in cents) · currency (three letters) · invoiceId (the idempotency key) · and at least one way to find the person: email, externalId, or clickId. Optional: name, eventName, metadata.
The tricky part
Linking an order to the clicked link
By email — the no-developer path
Subtraq finds the person by their email within the workspace attribution window — thirty days by default. If they clicked a tracked link and used the same email at checkout, the sale finds its link. This is exactly how the Stripe integration already works.
By click ID — that requires a developer
A Subtraq link passes a st_id parameter to its destination in the form clk_ followed by twenty-four characters. Getting it to the order means writing it to a cart attribute, which the Shopify documentation describes via a mutation of its Storefront API: that's development, not a setting.
What we haven't verified, we don't claim
No official page consulted on 12/09 states that Shopify preserves landing URL parameters through to the order. We don't promise it then. An integration relying on that would work by accident, and would stop one day without warning.
attributed: false is not a failure
The response says it plainly. An order whose email matches no known click is recorded, counted in revenue, and flagged as unattributed. That's the engine's rule: it never invents an origin.
Tricky cases, handled honestly
A store doesn't sell in a straight line. Here is what Subtraq does, and what it doesn't.
An order gets refunded. Does the number correct itself?
No, and you should know that before connecting. Shopify does publish a refunds/create topic, but Subtraq's sales route only accepts positive or zero amounts: a refund cannot be sent as a negative amount, and there is no call that cancels a recorded sale. The practical path: send a separate event with amount zero and a meaningful eventName to keep a trace — then correct the number manually in the report.
The same client orders twice in one week. Two sales?
Yes, two sales, and that's intentional: two order numbers, so two different invoiceId values. They join the same contact and the same origin link if the email is the same. What never counts twice is the same order number sent again on a retry.
A delayed payment, or an order paid three days later?
The trigger is Order paid: the request fires at payment, not at order creation. What matters then is the workspace attribution window — thirty days by default. A click older than the window no longer attaches, and the click cookie is also capped at thirty days: one rule for the same question.
What about without Shopify Flow, on a Basic plan?
A orders/paid webhook to Zapier, Make, or n8n, and the middleware sets the header that Shopify can't set. That's one more link in the chain, one more place it can break — but it's honest, and it works.
Frequently asked questions
Do I need to install a Shopify app?
No. No app to install, no line added to the theme, no pixel. Shopify Flow is part of the store admin on the plans that include it.
Do I need to modify the store theme?
Not for the method described here, which links the sale by email address. Yes if you want to carry the click ID all the way to the order: that requires a cart attribute, which means development.
Can the end customer see the server key?
It must never reach a browser. Stored in a Flow secret and called in Liquid, it stays server-side. That's also why amounts never go through the page pixel: a number written from a browser is worthless.
How long after a click can a sale still be attributed?
The client workspace's attribution window, thirty days by default, adjustable. Beyond that, the sale is recorded but not attributed.
What if Subtraq is unavailable when the order comes in?
The order exists in Shopify regardless, and Flow logs the failed action. Nothing is lost on the store side; only the sale recording is missing, and it can be resent with the same invoiceId without risk of duplication.
On a plan without Flow, use middleware
An orders/paid webhook to Zapier, Make, or n8n, and the middleware sets the Authorization header. Each guide shows the path in its interface.
The n8n guideYour next paid order can already know where it came from
Create an account, grab a server key, paste the URL into Flow. Your store does the rest.
Create a free account