Pagination, limits and errors
The rules every list endpoint and every error follows.
Formats
- Requests and responses are JSON, in UTF-8. Responses are never cached (
Cache-Control: no-store). - Field names are
snake_case. - Dates and times are ISO 8601 in UTC, for example
2026-10-29T14:30:00.000Z. - Money amounts are decimal strings with two places, such as
"1348.00", so no precision is lost. Currency is given alongside where it applies.
Pagination
List endpoints return one page at a time, newest first:
{
"data": [ ... ],
"has_more": true,
"next_cursor": "cm2abc123"
}| Parameter | Type | Description |
|---|---|---|
| limit | integer | Items per page, 1 to 100. Default 25. A missing or invalid value falls back to the default instead of failing. |
| cursor | string | Pass the previous response's next_cursor to get the next page. Stop when has_more is false. |
curl -H "Authorization: Bearer zlx_live_YOUR_KEY" \
"https://api.zargologix.com/v1/shipments?limit=50&cursor=cm2abc123"Staying in sync
To mirror ZargoLogix data in your own system, poll with updated_since (shipments) or created_since (invoices and quotes) and de-duplicate by id. A record that changes while you are paging can appear on two pages, so always upsert by id rather than inserting. For instant updates instead of polling, use webhooks.
Rate limits
Each key has a per-minute request limit (120 by default; ZargoLogix can set a different limit for a particular key). The limit that applies to you is always in the response headers:
| Header | Type | Meaning |
|---|---|---|
| X-RateLimit-Limit | integer | Requests allowed per one-minute window. |
| X-RateLimit-Remaining | integer | Requests left in the current window. |
| X-RateLimit-Reset | integer | Seconds until the window resets (not a timestamp). |
Over the limit you get 429 rate_limited with a Retry-After header (seconds). Wait that long, then retry. Counts are shared across all of a key's requests, however many servers send them.
Errors
Every error has the same shape:
{
"error": {
"code": "invalid_parameter",
"message": "status must be one of: DRAFT, PENDING_APPROVAL, APPROVED, ..."
}
}Use code in your program. The message is for people and may change.
| Code | Status | Meaning |
|---|---|---|
| invalid_parameter | 400 | A filter value is not valid, for example an unknown status or a date that is not ISO 8601. |
| unauthorized | 401 | Missing or invalid API key. |
| key_revoked | 401 | The key was revoked. |
| key_expired | 401 | The key has expired. |
| insufficient_scope | 403 | The key does not have the scope this endpoint needs. |
| not_found | 404 | No record matches the id you asked for. |
| rate_limited | 429 | Too many requests. See Retry-After. |
| internal_error | 500 | Something went wrong on our side. Retry after a moment; if it persists, check the system status page. |
- Retry
429and5xxresponses with a growing delay. Do not retry4xxresponses other than429without changing the request. - The public tracking endpoint uses a simpler error shape. See the Tracking page.