Errors & limits
Every failure comes back in the same shape, with a code that is safe to branch on.
The envelope
{
"error": {
"type": "invalid_request",
"code": "unknown_town",
"message": "That town is not one of our pickup towns. List them with GET /v1/towns.",
"param": "dest_town_id",
"request_id": "req_97515958f3975668c37281f2"
}
}Branch on code, never on message — messages are written for people and we improve their wording. param names the offending field, which is what you highlight in a form.
request_id. Every response carries one in the X-Request-Id header too, and quoting it turns a support conversation into a single lookup.Types
| Type | HTTP | Do |
|---|---|---|
authentication_error | 401 | Fix the key. Do not retry. |
permission_error | 403 | Key lacks a scope, or the account is not approved. |
invalid_request | 400 / 409 / 422 | Fix the request. Do not retry unchanged. |
not_found | 404 | Wrong id, or it belongs to another account. |
rate_limit_error | 429 | Back off and retry. |
api_error | 500 | Ours. Retry with backoff. |
Codes worth handling
| Code | Means |
|---|---|
insufficient_scope | The key may not do this. Names the missing scope. |
client_not_active | Live key, unapproved account. Test keys still work. |
unknown_town | Not a pickup town. Refresh your cached list. |
missing_destination | Send a town id or destination coordinates. |
not_quotable | Route outside the network. Fall back to your own shipping. |
parcel_not_cancellable | Already moving. Contact support. |
run_already_scanned | Your batch is locked for payment; the parcel is committed. |
rate_limited | Too many requests this minute. |
Rate limits
The default is 120 requests per minute per account, across all your keys. Every response tells you where you stand:
RateLimit-Policy: 120;w=60
RateLimit: limit=120, remaining=111, reset=22Over the limit you get 429. Back off rather than retrying immediately — and if you are hitting it legitimately, ask and we will raise it rather than having you engineer around it.
Caching towns and quotes is the cheapest way to stay well under.
Retrying safely
Reads are safe to retry. The one write that needs care is booking a parcel — always send X-Idempotency-Key so a retry replays the first result instead of creating a second parcel. See parcels.
Still stuck?
Email info@shopinn.co.ke with the request_id and roughly when it happened.
