Quickstart
Get your credentials, mint a token, and submit your first order. About ten minutes once you have access, entirely in the sandbox — nothing you do here reaches a real warehouse.
Credentials are issued by Kinimatic, not self-served. Tell us about your
integration and we will send you a client id and secret scoped to what you need —
ext:outbound:write and ext:outbound:read to start with, inbound
permissions added later.
The client secret is shown to you once, when we issue it. Store it somewhere your application can read at run time; if it is lost we rotate rather than resend.
Request accessExchange your client id and secret for a bearer token. Tokens last one hour.
Every order names the facility it ships from, by its facilityId. Call
GET /facilities to fetch the ones you are assigned to. An order naming a
facility you are not assigned to is refused with a 403.
Post the order with your own reference. You get a 202 and an order id
straight away — fulfilment continues in the background.
Do it against the sandbox first — a create there is free, and it is the same code path production runs, so a payload that works there works here.
Poll the order until it ships, or add a notification endpoint and we will post to you when it does. Most integrations do both: notifications for speed, polling as the safety net.
How webhooks workWhat to build next
An accepted order is not a shipped order. Watch for order.refused and
order.short_shipped — those are the ones a human needs to see.
Order lists change while you read them. Page numbers skip rows; cursors do not.
Back off for the number of seconds in Retry-After. Retrying immediately
makes it worse.
curl -X POST https://sandbox.api.kinimatic.com/oauth2/token \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=client_credentials" \ -d "client_id=$KINIMATIC_CLIENT_ID" \ -d "client_secret=$KINIMATIC_CLIENT_SECRET" \ -d "scope=ext:outbound:write ext:outbound:read" # → cache this for the full hour { "access_token": "eyJhbGciOi…", "token_type": "Bearer", "expires_in": 3600 }
curl -X POST "https://sandbox.api.kinimatic.com\ /outbound/ext/v1/orders" \ -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{ "orderNumber": "SO-000001", "facilityId": "019faa4e-4b53-…", "lines": [ { "sku": "2116", "orderedQty": 480, "uom": "EA" } ] }'
{
"orderId": "019ffd80-2c41-…-b7a9e2f10c33",
"orderNumber": "SO-000001"
}
Webhooks
We post a signed message to your endpoint when something happens to your orders. Verify the signature on every message, and expect repeats — we deliver at least once.
How delivery works
- Guarantee
- At least once. A message can arrive more than once — key your handler on
Kinimatic-Event-Idand make reprocessing a no-op. - Ordering
- Not guaranteed. Two events about the same order can arrive out of sequence; trust the timestamps in the body over arrival order.
- Retries
- Any non-
2xx, or no answer within 10 seconds, is retried with exponential backoff for 24 hours. - Pausing
- After 12 consecutive failures we stop sending and tell you. Nothing is lost — when the endpoint is healthy again we redeliver everything from the pause.
- Setup
- Endpoints, event subscriptions and signing secrets are configured for you when your integration is provisioned. Contact us to add or change one.
Verifying a message
# Every message carries these headers Kinimatic-Event-Id: evt_019ffd66a1c4f2 Kinimatic-Signature: t=1786709021,v1=8f3c…d41a Kinimatic-Attempt: 1 # Sign the timestamp and the raw body with your secret, # then compare with a constant-time equality check. signature = hmac_sha256(secret, f"{timestamp}.{raw_body}") # During rotation, accept EITHER active secret. # Reject anything older than 5 minutes.