Developer Portal

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

EventWhen it firesAct on it?
order.createdWe accepted your order and it has an id. Confirmation only
order.acceptedThe warehouse acknowledged it and will fulfil it. Confirmation only
order.refusedThe warehouse will not fulfil it. Carries a reason code. Yes
order.backorderedNot enough stock. Carries the shortfall per line. Yes
order.pickingPicking has started. The order can no longer be amended freely. Informational
order.shippedIt left the building. Carries carrier and tracking. Usually
order.short_shippedIt shipped, but with less than you ordered. Yes
order.cancelledThe cancellation took effect. Confirmation only
order.cancel_rejectedYou asked to cancel and the warehouse refused — too late. Yes
order.update_rejectedA staged amendment was refused by the warehouse. Yes

Inbound ASNs

EventWhen it firesAct on it?
asn.createdWe accepted your ASN.Confirmation only
asn.receivedA receipt was booked. Fires once per receipt, not once per ASN. Usually
asn.discrepancyWhat arrived does not match what you advised. Yes
asn.put_awayStock reached its location and is now available. Informational
asn.cancelledThe 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