Skip to content

Core concepts

Errors and rate limits

Response envelopes, error codes, and the usage headers that ride on every call.

Response envelopes

Products share a small set of shapes. Read the envelope before the payload.

  • TrackingMCP and the SchedulesMCP public surface wrap success in { "ok": true, "data": ... }.
  • AirCargoMCP and FreightRatesMCP return the payload under { "data": ... }.
  • LoadingMCP returns { "ok": true, "plan": { ... } }.
  • The TrackingMCP DCSA feed at /v2/events is the one exception. It follows the standard rather than our envelope, so it answers a bare JSON array and puts pagination in the response headers.

The keyed TrackingMCP surface returns a coded error object, so you can branch on the code and show the message:

{
  "ok": false,
  "error": {
    "code": "VALIDATION_ERROR",
    "message": "identifier_type is required",
    "severity": "warning"
  }
}

The open TrackingMCP endpoints answer a plain message instead, and they are explicit rather than silent:

{
  "ok": false,
  "message": "That number fails the ISO check digit, which almost always means one digit is off. Did you mean MEDU1234562?"
}

Codes you will meet on TrackingMCP

CodeStatusWhat it means
VALIDATION_ERROR400A required field is missing or out of range. Posting the wrong field names lands here.
UNAUTHORIZED401The key is missing, malformed or revoked.
UNIQUE_QUOTA_EXCEEDED402The add would pass the shipment quota on your plan.
CONTAINER_QUOTA_EXCEEDED402No container slot is free on your plan.
PAYG_SPEND_CAP_REACHED402Pay-as-you-go only: the add would cross the spend cap you set.
NOT_FOUND404No record with that UUID on your account.
REFERENCE_NOT_RESOLVABLE404No line recognises the reference.
ALREADY_TRACKED409You are already tracking that identifier.
CONTAINER_ADD_IN_PROGRESS409The same identifier is mid-add on another request.
RATE_LIMITED429Too soon after the last recheck of that box.
DB_ERROR, INTERNAL_ERROR500Our side. Retry.

The one that is not a failure

TRACKING_IN_PROGRESS arrives on a 202 from GET /v1/containers/lookup/{identifier}. The reference is registered and the carrier has not answered yet, so it is neither a success nor a not-found. It carries retry_after_seconds. Poll again on that delay rather than adding the box a second time.

Note that ok is false on that 202. Branch on the status code, not on ok alone, or a healthy in-progress lookup will read as an error.

FreightRatesMCP uses a structured error object:

{ "error": { "code": "not_found", "message": "No rate for that lane yet." } }

Status codes

CodeMeaning
200Success.
201Created. A TrackingMCP add answers this.
202Accepted and still resolving. See the note above.
400The request is malformed, or a required parameter is missing.
401The key is missing or not recognised.
402A quota or spend cap stands in the way.
404The identifier resolved to nothing, or the lane has no data yet.
405Wrong method. FreightRatesMCP is GET only.
409The same record is already tracked, or an identical request is in flight.
429You are over the rate limit. Back off and retry.

Error codes you will see in the FreightRatesMCP envelope include missing_key, invalid_request, not_found, method_not_allowed and server_error.

Rate limits and usage

Responses carry usage headers so you can watch your budget without a second call. Read them, and when you see 429, back off with a short exponential delay before retrying. Public endpoints are limited per IP; keyed endpoints are limited per account and plan.

Handling it well

  • Treat any non-2xx as a typed outcome, not a crash. Branch on the code.
  • Log the message. It is written to be read by a human on your side.
  • Do not hammer a 404. An identifier that fails the check digit will keep failing until it is corrected.
  • Do not retry a 409 ALREADY_TRACKED as if it were an error. Read the record you already hold.