Conventions & Errors
Requests
- Send
Accept: application/jsonon every request andContent-Type: application/jsonwhen the request has a body. - Path parameters
{ldv}are tracking numbers (LDV),{id}are numeric identifiers,{bda}a BDA. - Boolean query parameters accept
true/falseand1/0. - Dates in query parameters and request bodies use
YYYY-MM-DD.
Responses
Responses are always JSON (Content-Type: application/json), including errors.
- A single resource is returned as a bare object.
- A collection is returned as
{ "data": [...] }. Large collections are paginated:
{
"data": [ ... ],
"links": { "first": "...?page=1", "last": "...?page=8", "prev": null, "next": "...?page=2" },
"meta": { "current_page": 1, "from": 1, "last_page": 8, "per_page": 50, "to": 50, "total": 391 }
}| Query parameter | Default | Max | Description |
|---|---|---|---|
per_page | 50 | 200 | Items per page |
page | 1 | Page number |
Lists are ordered from the most recent item.
Value objects
The same structures are used everywhere, in requests and responses.
| Object | Shape | Notes |
|---|---|---|
| Date / time | "2026-09-03T10:26:54+02:00" | ISO 8601 with time zone offset |
| Money | { "amount": 12.5, "currency": "EUR" } | currency is optional in requests (default EUR) |
| Weight | { "value": 1.5, "units": "KG" } | Requests accept KG or G (default KG); responses always use KG |
| Dimensions | { "length": 30, "width": 20, "height": 10, "units": "CM" } | Requests accept CM or MM (default CM); responses always use CM |
| Address | { "street", "street2", "city", "province", "postalCode", "countryCode" } | countryCode ISO 3166-1 alpha-2; province is the 2-letter code for Italy |
| Party | { "name", "company", "address": Address, "phone", "email", "reference" } | Shipper, recipient, pickup address |
| Carrier | { "code": "fedex", "name": "FedEx", "contractCode": "...", "contractName": "..." } | code is the lowercase carrier identifier |
| Status | { "code": 5, "key": "delivered", "label": "Consegnata" } | See below; label is the Italian label shown in the web UI |
Shipment statuses
code | key | Meaning |
|---|---|---|
0, 1 | processing | Created, not yet handed to the carrier |
2 | shipped | Shipped |
3 | in_transit | In transit |
4 | out_for_delivery | Out for delivery |
5 | delivered | Delivered |
6 | held_at_depot | Held at depot (a stock / giacenza is open) |
7 | returned_to_sender | Returned to sender |
8 | undelivered | Not delivered |
9 | awaiting_instructions | Waiting for the client’s instructions |
10 | awaiting_collection | Waiting for collection at a pickup point |
Where a filter accepts a status (for example GET /shipments?status=), you can pass a key, a numeric code or a comma-separated mix: status=delivered,held_at_depot or status=5,6.
Errors
Every error uses the same envelope. code is stable and machine-readable, message is for humans (and may be localized), details is optional (field errors, carrier response, plan limits…).
{
"error": {
"code": "validation_failed",
"message": "The given data was invalid.",
"details": {
"recipient.address.postalCode": ["The recipient.address.postal code field is required."]
}
}
}| HTTP | code | When |
|---|---|---|
401 | unauthenticated | Token missing, expired or revoked |
402 | subscription_required · subscription_payment_failed · plan_limit_reached | No subscription, unpaid subscription or monthly plan limit reached. Only on endpoints that generate costs (POST /shipments, POST /pickups) and on POST /webhooks. details carries plan_limit and shipments_this_month |
403 | insufficient_scope · account_disabled · client_role_required · forbidden | Token or user not authorized; forbidden also when a contract code was issued to another account |
404 | not_found | Resource does not exist or belongs to another client; also no contract available for a shipment |
405 | method_not_allowed | |
409 | invalid_state | The operation is no longer possible (shipment already in a manifest or in transit, stock already instructed) |
422 | validation_failed | Invalid payload; details maps each field (dot notation) to its messages |
422 | shipment_rejected | The shipment or pickup was refused by the business rules or by the carrier; the reason is in message |
429 | rate_limited | Too many requests — see the limits below |
502 | carrier_error | The carrier or an external service did not answer |
503 | http_error | Service temporarily unavailable |
500 | internal_error | Unexpected error — retry later, contact support if it persists |
A 404 on a resource you just created almost always means you are calling with a token of a different client account (a different App or user). Resources are never shared across accounts.
Rate limits
Limits are per App, per minute. Exceeding one answers 429 rate_limited with the standard Retry-After / X-RateLimit-* headers.
| Endpoint | Limit |
|---|---|
POST /rates | 60 / min |
POST /shipments | 30 / min |
POST /pickups | 10 / min |
POST /manifests | 5 / min |
GET /shipments/{ldv}/tracking, GET /tracking/bda/{bda} | 20 / min (platform setting) |
GET /delivery-points | 30 / min |
GET /taric | 60 / min |
POST /webhooks/{id}/test | 5 / min |
For status updates prefer webhooks over polling the tracking endpoints.