Skip to main content
POST /rentals requires an Idempotency-Key header. It is the only endpoint that does, and the reason is narrow: creating a rental spends money, and a network timeout tells you nothing about whether it happened.

The problem it solves

Your request times out. Three things could have happened:
  1. It never reached us — no rental.
  2. It reached us and failed — no rental.
  3. It reached us and succeeded, and the response was lost — a rental you are now paying for and do not know about.
From the client, all three look identical. Without an idempotency key you have to pick between never retrying (and sometimes silently failing to start work) and always retrying (and sometimes paying for two machines). Neither is acceptable when the resource costs dollars per hour. With a key, the retry is safe: we recognise it and return the rental the first attempt created.

What a retry returns

Same key, same body → the original rental, with 201 and the original id. Not a new machine, not an error.

The three failure modes

The first attempt is still being processed. Rather than risk a second machine, we refuse and tell you how long to wait:
Wait and retry with the same key. A new key here would create the second machine you were trying to avoid.
We compare a canonical hash of the body, so key ordering and whitespace do not matter — {"a":1,"b":2} and {"b":2,"a":1} are the same request.The alternatives were both worse. Returning the first rental would hand you a machine that does not match what you just asked for. Creating a second would make the key meaningless. An error is the only answer that cannot mislead.The usual cause is a key derived from something too coarse — see below.

Choosing keys

One key per intent to create one rental. 8–255 characters; a UUID v4 is the easy right answer.
Generate the key outside the retry loop. A uuid4() inside the loop gives every attempt a fresh key, which is exactly the same as having no idempotency at all — and it fails in the worst possible way, by working perfectly until the one time the network is slow.

Deriving keys from your own ids

A deterministic key is fine, and often better, as long as it is unique per intent:
The test is simple: if two different rentals could ever produce the same string, the key is too coarse. A too-coarse key does not create a duplicate machine — it produces idempotency_key_reused and refuses to start the second rental at all, which is a confusing outage rather than a billing incident.

Scope and lifetime

  • Keys are scoped to your account. Two of your keys using the same string collide; another customer using it does not affect you.
  • Records are retained long enough to cover any realistic retry, then swept. A key reused weeks later may no longer be recognised — which is fine, since by then it is a new intent anyway.

Everything else

No other endpoint takes the header. It would be noise:
  • GET requests change nothing.
  • POST /rental-quotes reserves nothing and costs nothing.
  • POST /rentals/{id}/stop is idempotent by nature — stopping an already-stopping or already-stopped rental returns the rental as it is, not an error. Retry it freely.