API conventions
These conventions apply to every Carriyo API. Read this page once before building; the individual spec references assume you already know it.
Base URL
All production endpoints are under:
https://api.carriyo.com
A demo environment is also available at https://demo-api.carriyo.com. It shares the same contract as production — use it to validate an integration before going live.
Authentication
Every request requires two things:
Authorization: Bearer <token>— an OAuth 2.0 access token obtained from the Authentication API.tenant-id: <your-tenant-id>— your Carriyo tenant identifier, issued during onboarding.
A missing or expired token returns 401. A token that's valid but doesn't have access to the requested merchant or resource returns 403.
See Authentication for how to obtain and refresh tokens.
Versioning
The Carriyo API does not use URL path versioning (/v1/, /v2/). All endpoints are at the root path. Breaking changes follow a deprecation period: existing fields are marked deprecated and kept for at least one release cycle before removal. Additive changes (new fields, new enum values) are made without notice and are non-breaking.
Treat null or absent fields in responses as "not set", not as an error. New optional fields may appear in existing response shapes.
Request format
Send JSON with Content-Type: application/json. Bodies use snake_case field names throughout.
Dates and timestamps use ISO 8601 format with a timezone offset:
yyyy-MM-dd'T'HH:mm:ss.SSSXXX
Example: 2025-11-03T09:15:00.000+00:00. Timestamps without an offset are also accepted on input, but responses always include the offset.
Error responses
All errors return a JSON body in one of two shapes. Simple errors use errors — a list of human-readable strings:
{
"status": "400",
"timestamp": "2025-11-03T09:15:00.000+00:00",
"errors": [
"partner_shipment_reference : must not be blank"
]
}
Structured errors on shipment operations also return error_details alongside or instead of errors:
{
"status": "400",
"timestamp": "2025-11-03T09:15:00.000+00:00",
"error_details": [
{
"level": "ERROR",
"trigger": "VALIDATION",
"source": "CARRIYO",
"type": "MISSING_FIELD",
"message": "partner_shipment_reference is required",
"field": "partner_shipment_reference"
}
]
}
The status field is the HTTP status code as a string, mirroring the HTTP response status. Both errors and error_details may be present in the same response.
HTTP status codes
| Code | Meaning |
|---|---|
200 OK | Request succeeded. Response body contains the result. |
201 Created | Resource created. Response body contains the new resource. |
204 No Content | Request succeeded. No response body. |
400 Bad Request | Validation failed. Check errors or error_details in the response body. |
403 Forbidden | The token is valid but access to this resource or merchant is denied. |
404 Not Found | The requested resource does not exist. |
405 Method Not Allowed | The HTTP method is not supported on this path. |
409 Conflict | A concurrent write conflict occurred. Retry the request. |
429 Too Many Requests | Rate limit exceeded. Back off and retry. See Rate limits below. |
500 Internal Server Error | Unexpected server error. |
401 Unauthorized is returned by the API Gateway before requests reach the application — it means the Authorization header is missing, malformed, or the token is expired.
Rate limits
Rate limits are enforced at the API Gateway edge, per API key. Exceeding the limit returns 429 Too Many Requests. The limits are per second (sustained rate) plus a burst allowance for short spikes.
| Plan | Sustained rate | Burst |
|---|---|---|
| Free | 5 req/s | 50 |
| Starter | 10 req/s | 100 |
| Pro | 20 req/s | 200 |
| Enterprise | 50 req/s | 500 |
Your plan is set at the tenant level. Contact your account manager to change it.
When you receive a 429, wait before retrying. An exponential backoff strategy is recommended — start with a short pause and double it on each successive failure.
Idempotency
Most write operations are not idempotent. Sending the same request twice creates a second resource.
Two specific exceptions:
- Shipment
partner_shipment_reference— must be unique within your tenant. Reusing a reference that already exists returns400. This is a uniqueness guard, not an idempotency replay. - Inventory bulk import
request-idheader — if you supply the samerequest-idon a second call, the request is rejected with400. Look up the original batch byrequest-idusing the status endpoint instead.
There is no general-purpose Idempotency-Key header.