Skip to main content
Idempotency is a new feature only available in the upcoming API that is currently in beta. The behavior described below is subject to change until the API is released in General Availability.
Network errors, timeouts, and other transient failures can leave you uncertain whether a request actually reached Smart Send. Idempotency lets you retry such requests safely, without risk of booking the same shipment twice or creating duplicate resources.

How idempotency works

Idempotency is opt-in. To enable it, include an Idempotency-Key header on a write request:
Example
Idempotency-Key: order-4521_9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08
When the API receives a key it has not seen before, it processes the request normally and stores the response against that key. If you retry the same API request with the same key and the same payload within 24 hours, the API returns the stored response instead of running the operation again. The retry is therefore safe: eg. a shipment is booked once, even if you send the request twice. Requests sent without an Idempotency-Key header are not deduplicated. Each one is processed independently.
Idempotency applies to write operations (POST and DELETE). Read operations (GET) are already safe to retry, so they ignore the header. When a stored response is replayed, the API includes an Idempotency-Replayed: true response header so you can tell a replay apart from a freshly executed request.

Creating an idempotency key

The key is a string that uniquely identifies a single logical operation. It must meet these requirements:
RequirementValue
Length16–128 characters
Allowed charactersLetters, digits, ., _, -
CaseCase-sensitive (ABC and abc are different keys)
ScopeUnique per operation, per client
A random UUID v4 works, but it forces you to generate the key up front and store it alongside the order so you can reuse the exact same value on a retry. A simpler approach is to derive the key deterministically from data you already have, such as the order ID combined with the request payload. Because the same inputs always produce the same key, a retry recomputes the identical key without you having to store anything:
// $orderId is your own order reference; $payload is the exact body you will send.
$key = $orderId . '_' . hash('sha256', json_encode($payload));

// $key is your order reference followed by a 64-character hex hash, e.g.
// "order-4521_9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08"
Send the derived value in the Idempotency-Key header. If the request fails and you retry, recompute the key from the same order and payload, and the API recognises it as the same operation.
Including the payload in the key means that a different payload produces a different key, which the API treats as a new operation. If you instead key on a stable identifier alone (for example just the order ID), reusing it with a changed payload is reported as a conflict — see below.

How repeated requests are handled

SituationResult
New keyThe request is processed normally and the response is stored.
Same key, same payload, original finishedThe stored response (status code and body) is returned without re-executing the operation. The response includes the header Idempotency-Replayed: true.
Same key, different payload422 Unprocessable Entity. The key is already associated with a different request.
Same key, original still in progress409 Conflict with a Retry-After header indicating how many seconds to wait before retrying.
Keys are scoped per client and expire automatically 24 hours after first use. After that, the same key can be used again for a new operation.
A request that fails validation is not stored against the key. You can correct the payload and retry with the same key.

Conflicts and errors

If you receive a 409 Conflict, the original request is still being processed. Wait for the number of seconds given in the Retry-After response header, then retry with the same key:
Example response
HTTP/1.1 409 Conflict
Retry-After: 1
A 422 Unprocessable Entity means the key has already been used for a request with a different payload which is considered wrong. Either reuse the original payload, or generate a new key for the new operation.