Retrying safely
A call can time out after we received it, so your system can't always tell whether it worked. Sending it again is safe for some calls and harmful for others: a second Create a waybill books the carrier again.
The API has no idempotency keys, so recover by reading first. The table says, for each call that changes something, what a second identical request does and how to recover.
| Call | If you send it twice | After a timeout |
|---|---|---|
| Sign in | You get a second token. Both work for a week. | Retry. |
| Create a quote | A second quote is made. An unbooked quote costs nothing. | Retry. Ignore the extra quote. |
| Create an order | No second order: a quote can hold one order. The second request answers 422 "The order could not be placed…", which doesn't say the order exists. | Look first. Send your own unique customer_reference with every order, then search for it with List orders ?q=<customer_reference>. If an order with your quote's quote_id is there, it worked. Otherwise send the same request again. |
| Create a waybill | The carrier is booked again, even if the first call worked. The waybill number changes and the first booking is left behind. Two calls at once both book. | Never retry blindly. Wait a minute, read the order with Get an order, and call again only if it still has no waybill (on a hub order, none of shipments[].waybill). |
| Book a pickup | The first pickup is cancelled and a new one booked. A slot the carrier doesn't offer is refused first, so the first pickup stays. If the carrier refuses the new booking, the first pickup is already cancelled and you are left with none. | Look first. List pickups answers newest first. If the latest is scheduled for the slot you asked for, it worked. If it is system_to_schedule, it is still being booked: wait. Book again only if there is none, or the latest is errored, missed or cancelled. |
| Cancel an order | The second call answers 200 again. | Retry. A 200 means it is cancelled. |
| Create a company | The second request answers 422 "Name has already been taken". Two requests sent at the same moment can make two companies. | Look first with List companies ?q=<name>. A 422 "Name has already been taken" after a timeout most likely means the first call worked. |
| Create a webhook | A second webhook is made, with its own token, so every event reaches you twice. There is no call to list your webhooks. | Don't retry blindly. If you did, keep both tokens and ignore duplicate events (see Receiving webhooks), or ask your account manager to remove the extra one. |
| Update a webhook | The same values are saved again. | Retry. |
| Delete a webhook | The second call answers 404. | Retry. Treat a 404 as deleted. |
Reading calls (every GET) are always safe to retry.
Rate limits
Create a quote, Create an order and the Companies calls take 20 requests a minute from one address. Past that they answer 429 "Too many requests, please wait and try again" until the minute is up. Failed calls count too, and there is no Retry-After header: wait a minute before trying again.
Timeouts
Give a call at least 60 seconds before giving up. Create a quote asks every carrier for a price, and Create a waybill books the carrier, so both can take a while.