# 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](/reference/sign-in) | You get a second token. Both work for a week. | Retry. |
| [Create a quote](/reference/create-a-quote) | A second quote is made. An unbooked quote costs nothing. | Retry. Ignore the extra quote. |
| [Create an order](/reference/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](/reference/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](/reference/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](/reference/get-an-order), and call again only if it still has no `waybill` (on a hub order, none of `shipments[].waybill`). |
| [Book a pickup](/reference/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](/reference/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](/reference/cancel-an-order) | The second call answers `200` again. | Retry. A `200` means it is cancelled. |
| [Create a company](/reference/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](/reference/list-companies) `?q=<name>`. A `422` "Name has already been taken" after a timeout most likely means the first call worked. |
| [Create a webhook](/reference/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](/guides/webhooks)), or ask your account manager to remove the extra one. |
| [Update a webhook](/reference/update-a-webhook) | The same values are saved again. | Retry. |
| [Delete a webhook](/reference/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](/reference/create-a-quote), [Create an order](/reference/create-an-order) and the [Companies](/reference/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.
