# What is an idempotency key? An idempotency key is a unique string sent with a write so the server can spot a retry and return the first result instead of acting twice. **On Runtime every write carries an idempotency key, and both SDKs make one for you and retry with it,** so a create whose reply was lost never makes a second sandbox and a retried command never runs twice ([errors and retries](/docs/javascript#errors-and-retries)). The server remembers each key for 24 hours. ## Why it matters for AI agents Networks drop replies. When a create request times out, the client cannot tell whether the server never saw it or finished it and the answer got lost. A retry without a key may start a second machine, billed and forgotten. A retried `exec` may run `git push` or a payment call a second time. Agents make this worse: they retry by design, often from a fresh process after a crash, and an MCP client may repeat a tool call it thinks failed. An idempotency key turns "did that happen?" into a question the server answers. ## How Runtime treats a key | Request | What the server does | | -------------------------------- | ---------------------------------------------------------------------------------- | | Same key, same body | Answers the first result again, with `"replayed": true` | | Same key, different body | Refuses with 422 `idempotency_key_reused` | | New key | Treats it as new work | | Header | `Idempotency-Key: `; a replay adds `Idempotency-Replayed: true` | | How long a key is kept | 24 hours | | What the SDKs retry with the key | Transport failures, 429, 502, 503 and 504, with a growing delay | A failed [fork](/glossary/sandbox-fork) is over: a retry with the same key answers the same error, so fork again with a new key ([API](/docs/api#retries-and-idempotency)). ## Survive a process restart The key the SDK makes lives only as long as the call. To make a retry safe after your own process dies, derive the key from the job, so the next attempt sends the same one: ```ts import { Runtime } from "withruntime"; const runtime = new Runtime(); const job = "invoice-run-2026-09-25"; const input = { labels: { job } }; await using sbx = await runtime.sandboxes.create(input, { idempotencyKey: `create-${job}` }); console.log(sbx.id); // a retry within 24 hours answers this same sandbox ``` Keep the body identical on the retry. Changing the input under the same key is not a retry, and the server says so. ## Keys over MCP An agent calling Runtime's MCP tools directly should choose and record a unique `idempotencyKey` before the first call, and reuse it with identical input after a lost reply. A key the server generated for an omitted field cannot be recovered from a lost reply, so read the resource before repeating that write ([MCP](/docs/mcp)). When a command's outcome is still unknown after a timeout, inspect its files and processes before repeating a side effect ([troubleshooting](/docs/troubleshooting)). ## Related - [What is an agent loop?](/glossary/agent-loop) - [What is tool calling?](/glossary/tool-calling) - [API errors and retries](/docs/api#retries-and-idempotency) - [How to choose a sandbox for AI agents](/docs/choosing-agent-sandbox) Facts on this page were checked on 25 September 2026.