Event catalog
Every event we can send you, what it means, and what it carries. Your subscriptions are configured when your integration is set up — see how webhooks work.
These names are frozen. They are a public vocabulary, separate
from our internal event names, so we can rename things inside the platform without
changing what arrives at your endpoint. A new event type is additive; an existing one never
changes meaning.
Outbound orders
| Event | When it fires | Act on it? |
|---|---|---|
| order.created | We accepted your order and it has an id. | Confirmation only |
| order.accepted | The warehouse acknowledged it and will fulfil it. | Confirmation only |
| order.refused | The warehouse will not fulfil it. Carries a reason code. | Yes |
| order.backordered | Not enough stock. Carries the shortfall per line. | Yes |
| order.picking | Picking has started. The order can no longer be amended freely. | Informational |
| order.shipped | It left the building. Carries carrier and tracking. | Usually |
| order.short_shipped | It shipped, but with less than you ordered. | Yes |
| order.cancelled | The cancellation took effect. | Confirmation only |
| order.cancel_rejected | You asked to cancel and the warehouse refused — too late. | Yes |
| order.update_rejected | A staged amendment was refused by the warehouse. | Yes |
Inbound ASNs
| Event | When it fires | Act on it? |
|---|---|---|
| asn.created | We accepted your ASN. | Confirmation only |
| asn.received | A receipt was booked. Fires once per receipt, not once per ASN. | Usually |
| asn.discrepancy | What arrived does not match what you advised. | Yes |
| asn.put_away | Stock reached its location and is now available. | Informational |
| asn.cancelled | The ASN was withdrawn. | Confirmation only |
The five marked "Yes" are the ones that
need a human or a rule. Everything else is confirmation. An integration that only handles
the happy path will look healthy and quietly lose orders.
Delivery guarantees
At least once: not exactly once
You will occasionally get the same event twice. Dedupe on eventId,
which is stable across redeliveries and replays.
Ordered per order: not globally
Events about one order arrive in sequence. Events about different orders can arrive in any order relative to each other. Never assume a global ordering.
sequence: gap detection
Increments per order. A gap means something did not arrive — read the order to catch up rather than waiting.
Delivery target: not an SLA
We aim to deliver promptly and retry with backoff. If your endpoint keeps failing we pause it and tell you, rather than retrying forever.
Envelope
{
// envelope — the same on every event
"eventId": "evt_019ffd66a1c4f2",
"type": "order.refused",
"apiVersion": "v1",
"occurredAt": "2026-08-14T09:41:02Z",
"sequence": 4,
// data — the shape depends on "type"
"data": {
"orderNumber": "SO-884209",
"facilityId": "019faa4e-4b53-…",
"reasonCode": "LOT_EXPIRED",
"reason": "Requested lot is past its expiry date.",
"lines": [
{ "lineNumber": "1",
"sku": "2116",
"reasonCode": "LOT_EXPIRED" }
]
},
"links": {
"order": "/outbound/ext/v1/orders?orderNumber=SO-884209"
}
}
Headers on every delivery
Kinimatic-Event-Id: evt_019ffd66a1c4f2 Kinimatic-Signature: t=1786709021,v1=8f3c…d41a Kinimatic-Attempt: 1 Content-Type: application/json
Handling it
# 1. verify the signature before parsing anything # 2. return 2xx fast — do the work after # 3. dedupe on eventId; you WILL see repeats if seen(event["eventId"]): return 200 if event["type"] == "order.refused": queue_for_review(event["data"]) return 200 # anything else is a retry