Orders API
Stores that are not on a platform Diverge connects to directly send their orders through the Orders API. Your backend sends the whole current order every time it changes; your checkout copies one opaque value, the visitor stamp, into each order.
Diverge never receives money from the browser: order totals, refunds and returns come only from your backend.
Set up in the dashboard
- Open Integrations → Custom store (Orders API) and choose Add store.
- Name the store and select the chatbots that run on its storefronts. Each chatbot is one market of the store; a chatbot belongs to one store at a time.
- Create a live key and a test key. The full key is shown once, so store it in your backend's secret store right away.
- Note the stamp cookie of each chatbot, shown on the store:
di_stamp_<chatbot_id>.
Only organization owners can manage stores and keys.
Step 1: capture the visitor stamp at checkout
The Diverge script keeps a stamp for each visitor on your own domain. Save it on the order when the order is created. Treat it as opaque: store and send it unchanged, never parse it. Its format can change without you changing anything.
Diverge signs every stamp. An edited or made-up stamp is reported as unrecognized and the
order is not linked to a visitor. A linked order records which visitor's stamp it carried; it does
not prove who placed the order. A chatbot starts getting stamps on its next page load after it
joins a store (allow up to a minute for caches); a page that was already open gets one when the
script next loads its settings.
Server-rendered checkout on the same domain: read the cookie in your checkout handler.
const stamp = req.cookies[`di_stamp_${DIVERGE_CHATBOT_ID}`] ?? null;
order.divergeStamp = stamp;Headless storefront, or checkout on another domain: read it in the browser and send it with the checkout request.
const stamp = (await window.DialogIntelligens?.getVisitorStamp?.()) ?? null;
await fetch("/api/checkout", {
method: "POST",
body: JSON.stringify({ ...cart, divergeStamp: stamp }),
});The stamp is missing when the Diverge script is not on the page. Leave the field out in that case: the order still counts in store totals, it is just not linked to a visitor.
Step 2: send order snapshots
Send the whole current order whenever it changes: placed, paid, cancelled, edited, refunded or returned. Authenticate with HTTP Basic: the commerce key is the username and the password is empty.
curl -X PUT https://api.dialogintelligens.dk/api/v1/commerce/orders/100234 \
-u "live_cs…:" -H "Content-Type: application/json" -d @order.json{
"order_number": "100234",
"placed_at": "2026-10-01T14:03:11Z",
"updated_at": "2026-10-01T14:05:42.120Z",
"currency": "DKK",
"total": "1299.00",
"subtotal": "1199.00",
"discount_total": "100.00",
"shipping_total": "49.00",
"tax_total": "259.80",
"payment_status": "paid",
"cancelled_at": null,
"sales_channel": "web",
"test": false,
"visitor_stamp": "v0.eyJj…",
"line_items": [
{
"line_id": "1",
"product_id": "8812",
"variant_id": "8812-42",
"sku": "TS-RED-42",
"quantity": 2,
"unit_price": "599.50",
"total": "1199.00"
}
],
"refunds": [
{
"refund_id": "r1",
"created_at": "2026-10-05T09:12:00Z",
"amount": "599.50",
"line_items": [{ "line_id": "1", "quantity": 1 }]
}
],
"returns": [
{
"return_id": "ret1",
"received_at": "2026-10-04T16:40:00Z",
"line_items": [{ "line_id": "1", "quantity": 1 }]
}
]
}| Field | Rule |
|---|---|
placed_at, updated_at, currency, total, payment_status | Required. updated_at must increase with every change to the order. |
| Amounts | Decimal strings in the shop's own currency, with no more decimals than the currency allows (DKK 2, JPY 0). |
total | What the customer pays, including VAT and shipping. Diverge calculates the net value from refunds. |
payment_status | pending, authorized, paid, failed or voided. |
refunds and returns | A refund is money back; a return is goods received back. Send whichever happened. |
product_id, sku | Use the ids of the product feed the chatbot uses. |
chatbot_id | Only for stores with several chatbots, to credit a market when the order has no stamp. The stamp wins. |
| Customer data | There are no name, email or address fields. Requests with unknown fields are refused, so none slip in. |
Responses
| Status | Meaning |
|---|---|
200 | result is applied (stored), stale (a newer version is stored) or unchanged (identical). |
409 | conflict: same updated_at but different content. Increase updated_at and resend. |
410 | gone: the order was erased and cannot be recreated. |
413 | payload_too_large: the body is over 4 MB. Send fewer orders per batch. |
422 | validation: params names each failing field. |
429 | rate_limited: wait the number of seconds in Retry-After, then retry. |
401 | unauthorized: the key is missing, wrong or revoked. |
Errors share one shape: { "error": { "code": "…", "message": "…", "params": [...] } }.
Other operations
| Method | Path | Purpose |
|---|---|---|
POST | /api/v1/commerce/order-batches | Up to 100 snapshots, each with its order_id. See batches. |
GET | /api/v1/commerce/orders/{order_id} | The order as Diverge stores it, to check an integration. |
DELETE | /api/v1/commerce/orders/{order_id} | Erases the order, e.g. for a deletion request. Later snapshots answer 410. |
GET | /api/v1/commerce/connection | The key's store, environment, chatbots and when the last order arrived. |
The full schema is in the API reference.
Batches
A batch is checked as a whole first: if any snapshot is malformed (a missing field, an unknown
field, an amount that is not a decimal string), the whole request answers 422 and lists the
fields, for example orders.2.total, and nothing is stored. Otherwise each order is stored on
its own and the response has one result per order: applied, unchanged or stale, or an
error (validation, conflict or gone) for that order only, such as a JPY amount with
decimals or an erased order.
Step 3: keep it correct
- Send from a queue or outbox so checkout never waits for Diverge. Retry on
5xxand429. - Once a night, resend every order updated in the last 7 days through
/order-batches. Sending the same snapshot again is safe, and it repairs anything a failed request missed. - Each key can make 600 requests a minute. A batch counts as one request.
Step 4: test
- Use the
test_key. Test orders are kept apart from live data. - Place an order after chatting, refund one line and cancel another order.
- On the store in Integrations, the test line shows the orders, and how many are linked to a visitor.
Privacy
- Order snapshots contain no customer contact or address data.
- When a customer asks you to delete their data, call
DELETE /orders/{order_id}for their orders. Diverge keeps only a keyed digest of the order id, to refuse later snapshots of it. - When a visitor deletes their chatbot data, Diverge removes their link from every order, and later snapshots of those orders are stored without it. Their browser then starts over as a new visitor with a new stamp, so only what they do afterwards can be linked again.