One API. Every warehouse.
Typed HTTP. Idempotency-Key on every write. Webhooks on every state change. Node and Python SDKs wrap the same endpoints.
POST /v1/inventory/ledger
Authorization: Bearer sk_live_...
Idempotency-Key: 3f9a8e21...
{ "sku": "SKU-0042", "warehouse": "SEA-1",
"delta": -12, "reason": "order_shipped" }POST the ledger.
Every write accepts an Idempotency-Key. Duplicates return the original response, byte-for-byte.
POST /v1/inventory/ledger HTTP/1.1
Host: api.skutrail.com
Authorization: Bearer sk_live_...
Idempotency-Key: 3f9a8e21-0c4d-4f7e-9e6b-2a8d5c1f1abc
Content-Type: application/json
{
"sku": "SKU-0042",
"warehouse": "SEA-1",
"delta": -12,
"reason": "order_shipped",
"reference": "ord_8J2kP"
}
HTTP/1.1 200 OK
Content-Type: application/json
{
"id": "ledger_7b...",
"sku": "SKU-0042",
"warehouse": "SEA-1",
"delta": -12,
"balance": 1196,
"applied_at": "2026-04-21T14:03:22Z"
}Idempotent by default.
Retries are free. Send the same Idempotency-Key twice; the second request is a no-op with the first response. Network loss stops being a data problem.
One key, one write
Same key → same result. Idempotency-Key is required on all writes.
24-hour window
Keys are valid for 24 hours. After that, re-send with a new key.
Webhook on every write.
Every state change fires a signed webhook. Verify the signature, deduplicate on the event ID, and you have a system of record that moves with your stack.
Rate limits per key, not per tenant.
Burst within your key's ceiling; the next second resets. Headers name the remaining budget on every response; no surprise 429s during peak.
X-RateLimit-Remaining
Every response carries the budget remaining.
Burst plus sustained
Short bursts absorbed; sustained load stays smooth.
Client, write, webhook.
Idempotent writes. Webhooks on every write.