Cargoplot API
API docs
OpenAPI spec

Errors

Two shapes, and how to tell them apart

Errors come back in one of two shapes depending on how far into the system your request got. Handle both — a client that parses only one will throw on the other exactly when something is already going wrong.

Rejected at the door — authentication and the API's own rate limiting:

json
{ "message": "invalid API key" }

Rejected by the endpoint — anything the API itself refused:

json
{
  "code": 3,
  "message": "limit must be at most 100, got 5000"
}

The safe way to read both: use the HTTP status for control flow, and message for the human. Both shapes always carry message, so logging response.message works either way.

One case carries neither shape: a request stopped by the per-IP edge ceiling never reaches the API, and comes back as the gateway's HTML error page. That is the one place a message lookup throws — see what you will not get.

The code in the second shape is not the HTTP status. It is a gRPC status code, because these endpoints are generated from service definitions — 3 is invalid argument, 5 is not found. If you are branching on anything, branch on the HTTP status.

Status codes

StatusMeaningWorth retrying?
400Your request was malformed — a bad limit, both cursors at once, an unknown enum value (glossary)No. Fix the request.
401Missing, malformed or revoked tokenNo. See authentication.
404No such record, or not one you can seeNo.
429Rate limit exceeded — your token's quota, or the per-IP edge ceilingYes. After Retry-After if the response carries one, otherwise back off.
500Something broke on our sideYes, with backoff. Report it if it persists.
503No healthy backend behind the edgeYes, with backoff.

A 404 covers both "this does not exist" and "this exists but is not yours". That is intentional: distinguishing them would let anyone confirm whether a reference belongs to another company.

Retrying

Retry 429, 500 and 503. Do not retry 400, 401 or 404 — the same request will fail the same way, and a loop around a 401 is how a token ends up locked out of a log file rather than fixed.

For 429, wait the Retry-After seconds when the response carries one. The edge ceiling does not send the API's headers, so back off exponentially there instead. For 500 and 503, do the same and give up after a handful of attempts rather than hammering a service that is already unwell.

Every read on this API is safe to repeat: nothing here changes state, so a retry can never double-apply anything.

What you will not get

  • No HTML from the API. Everything the API itself refuses is JSON. The exception is the per-IP edge ceiling: it is enforced in front of the API and serves the gateway's own HTML error page, so do not assume a 429 body is parseable — check the RateLimit-* headers instead.
  • No stack traces or internal detail. A 500 tells you it failed, not what our database was doing. If you need to know, quote the time and the endpoint in a support request.
  • No partial pages. A list request either returns a page or an error. It will not return half the records and an error field.