Documentation/Integrations and API·4 min read·Updated Nov 7, 2026
API overview
The Shipment Insight API will let your systems create shipments, read tracking and predictions, and manage webhooks over REST and JSON. This page is a preview of how it will work; details may change before launch.
Preview
The public API is not available yet. Everything here describes the planned design so you can prepare your integration. Endpoints and fields may still change before launch.
Basics
| Style | REST, with JSON request and response bodies. |
| Base URL | https://api.example.com/v1 (a placeholder: the real address will be announced at launch). |
| Format | UTF-8 JSON. Times are ISO 8601 in UTC, for example 2026-11-07T18:40:00Z. |
| IDs | Opaque strings. Store them as text and don't parse them. |
| Specification | An OpenAPI 3.1 file will be published with the API. |
Authentication with API keys
Every request needs an API key in the Authorization header. Admins will create keys in Settings. Each key has scopes that limit what it can do, for example reading shipments but not changing them.
| Prefix | Use |
|---|---|
si_live_ | Your real data. |
si_test_ | A sandbox with test data. Test keys never touch live data. |
curl https://api.example.com/v1/shipments/shp_0123456789 \
-H "Authorization: Bearer $SI_API_KEY"Keep keys secret
A key is shown only once, when it's created. Store it in a secrets manager, never in code or in a browser app. If a key leaks, revoke it in Settings and create a new one.
- Give each integration its own key with only the scopes it needs.
- Rotate keys with an overlap period, so your integration has no downtime.
- Each key shows when it was last used, which helps you find and remove unused keys.
Safe retries with idempotency keys
Networks fail. To retry a POST without creating a duplicate, send an Idempotency-Key header with a unique value (a UUID works well). If the same key arrives again, you get the original response back instead of a second shipment.
curl https://api.example.com/v1/shipments \
-X POST \
-H "Authorization: Bearer $SI_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1c2a9e-3b7d-4e1a-9c55-0d2f8e4b7a10" \
-d '{
"reference": "LD-880142",
"mode": "FTL",
"stops": [
{ "type": "pickup", "facility_id": "fac_montreal_01", "appointment": "2026-11-08T13:00:00Z" },
{ "type": "delivery", "facility_id": "fac_chicago_02", "appointment": "2026-11-09T19:00:00Z" }
]
}'Pagination
Lists are returned in pages. Use limit to choose the page size. Each response includes a next_cursor; pass it as cursor to get the next page. When next_cursor is null, you've reached the end.
curl "https://api.example.com/v1/shipments?status=in_transit&limit=50&cursor=eyJpZCI6..." \
-H "Authorization: Bearer $SI_API_KEY"{
"data": [
{ "id": "shp_0123456789", "reference": "LD-880142", "status": "in_transit" }
],
"next_cursor": "eyJpZCI6InNocF8wMTIzNDU2Nzg5In0"
}Rate limits
Each key can make a limited number of requests per minute. If you go over, you get 429 Too Many Requests with a Retry-After header that says how many seconds to wait. Wait at least that long, then retry, ideally with exponential backoff.
HTTP/1.1 429 Too Many Requests
Retry-After: 12
Content-Type: application/jsonTip
Instead of polling for changes, subscribe to webhooks. You get updates as they happen and stay well within your limits.
Errors
Errors use standard HTTP status codes and always return the same JSON shape, with a stable code you can handle in your program and a message for people. Include the request_id when you contact support.
{
"error": {
"code": "validation_failed",
"message": "stops[1].appointment must be after stops[0].appointment",
"request_id": "req_01HZX4N8Q2"
}
}| Status | Meaning |
|---|---|
400 | The request is invalid. Fix it before retrying. |
401 | The API key is missing, wrong, expired or revoked. |
403 | You can see this resource, but your key's scopes don't allow this action. |
404 | Not found, or not available to you. See below. |
409 | Conflict, for example the same Idempotency-Key reused with a different body. |
429 | Too many requests. Wait for Retry-After. |
5xx | A problem on our side. Retry with backoff. |
Why you get 404 instead of 403
If you ask for something that belongs to another organization, or that your key isn't allowed to see, the API answers 404, exactly as if it didn't exist. This way the API never confirms that someone else's shipment exists. You get 403 only when you can already see the resource but can't perform one specific action on it. The same rule applies in the console: see Roles and access.
Versioning
- The version is in the path:
/v1. - Within a version we only add things: new endpoints, new optional fields, new event types. Your code should ignore fields it doesn't know.
- Breaking changes go into a new version. The old one keeps working for a deprecation period announced in the Changelog.