API Reference
Developer Guide
Rate Quote endpoint
All rate requests use a single endpoint regardless of platform. The platform is identified via the X-Platform request header, which the first-party plugins set automatically.
POST /api/v1/quotes
Content-Type: application/json
x-api-key: YOUR_API_KEY
X-Platform: magento2 | shopify | bigcommerce | commercetools | customThe full OpenAPI specification is available in the interactive Swagger UI.
Request payload
{
"destination": {
"country": "GB", // ISO 3166-1 alpha-2 country code (required)
"postcode": "SW1A 1AA", // Postal / ZIP code
"city": "London", // Destination city (optional)
"region": "England" // State / county / province (optional)
},
"items": [
{
"sku": "WIDGET-001",
"name": "Blue Widget",
"quantity": 2,
"unitPrice": 2499, // Unit price in smallest currency unit (pence/cents)
"weight": 1.25, // Unit weight in the store's unit (kg or lb)
"dimensions": { // Optional — per unit, in the store's unit (cm or in)
"length": 30,
"width": 20,
"height": 10
},
"tags": ["fragile"] // Routing tags (may be empty)
}
]
}| Field | Type | Required | Description |
|---|---|---|---|
destination.country | string | Yes | ISO 3166-1 alpha-2 country code (e.g. GB, US) |
destination.postcode | string | No | Postal or ZIP code — primary zone matching key |
destination.city | string | No | Destination city name — accepted and validated, but has no effect on zone matching or rating |
destination.region | string | No | State or region — accepted and validated, but has no effect on zone matching or rating |
items | array | Yes | Line items in the cart (see item fields below) |
currency | string | No | Override currency (GBP/USD/EUR/AUD/CAD) — defaults to the store currency |
strategy | string | No | cheapest or fastest — overrides the store quote strategy |
quoteDate | string | No | ISO 8601 date or datetime that scheduled rate tables and carriers are evaluated against — defaults to now. Also varies the cache key. See Scheduling |
explain | boolean | No | When true, the response includes an explain object listing every rate table considered, matched or skipped with a reason. Bypasses the cache and does not change the returned rates |
Item fields
| Field | Type | Required | Description |
|---|---|---|---|
sku | string | Yes | Product SKU or ID |
name | string | No | Product name |
quantity | number | Yes | Quantity ordered |
unitPrice | number | Yes | Unit price in the smallest currency unit (pence/cents) |
weight | number | Yes | Unit weight in the store's configured unit (kg or lb) |
dimensions | object | No | Per-unit length, width and height in the store's configured dimension unit (cm or in). Required for dimensional rate tables to compute a volumetric weight — without it only the actual weight is billable |
tags | string[] | No | Routing tags — see Tags & Routing |
Response format
A 200 OK response is wrapped in an envelope: success plus a data object holding the quote. The rates array inside data contains every available shipping method — all entries returned are offerable (there is no separate availability flag to filter on).
{
"success": true,
"data": {
"quoteId": "f1e2d3c4-...",
"rates": [
{
"id": "uuid", // fresh per request — not a durable rate id
"carrierName": "Royal Mail",
"carrierCode": "royal-mail",
"serviceName": "Tracked 48",
"amount": 399, // smallest currency unit (pence/cents)
"currency": "GBP",
"displayAmount": "£3.99",
"minDeliveryDays": 2,
"maxDeliveryDays": 3,
"validFrom": null,
"validTo": null
}
],
"totalWeightGrams": 700,
"totalValueAmount": 3998,
"currency": "GBP",
"zoneName": "UK Mainland", // null when no zone matched
"cached": false,
"quoteDate": "2026-06-04",
"calculatedAt": "2026-06-04T10:00:00.000Z",
"responseMs": 18
}
}Errors are not enveloped — a failed request returns { statusCode, error, message, timestamp, path } at the top level. Check the HTTP status rather than the success field.
| Field | Type | Description |
|---|---|---|
quoteId | string | Unique identifier for this quote |
rates | array | Available shipping methods (see rate fields below) |
totalWeightGrams | number | Total basket weight in grams — every unit of every line, after conversion from the store's weight unit |
totalValueAmount | number | Total basket value in the smallest currency unit (pence/cents) |
zoneName | string | The shipping zone matched for this destination — null when none matched |
cached | boolean | Whether the result was served from cache |
quoteDate | string | The datetime the scheduled rate windows were evaluated against — echoes the request's quoteDate, or the time of the request when it was omitted |
Rate fields
| Field | Type | Description |
|---|---|---|
carrierName | string | Display name for the carrier (e.g. Royal Mail) |
carrierCode | string | Stable, machine-readable carrier identifier |
serviceName | string | Display name for the shipping method (e.g. Tracked 48) |
amount | number | Price in the smallest currency unit (pence/cents) |
currency | string | ISO 4217 currency code |
displayAmount | string | Pre-formatted price for display (e.g. £3.99) |
minDeliveryDays / maxDeliveryDays | number | Estimated delivery window, when configured on the carrier |
validFrom / validTo | string | null | The scheduled window this rate is available within — the rate table's window, falling back to the carrier's when the table has none. null = unbounded. See Scheduling |
Error codes
| Status | Meaning |
|---|---|
200 | Success — data holds the quote object. data.rates may be empty (and data.zoneName null) when no zone matched the destination; this is a success, not an error |
400 | Malformed request — a required field is missing or mistyped, or the payload contains a field the API does not recognise. Unknown fields are rejected rather than ignored |
401 | Missing or invalid x-api-key |
403 | Store is suspended, or still pending activation |
429 | Rate limit exceeded — 100 requests per 60 seconds, per IP |
500 | Internal server error — check the health status page for ongoing incidents |