# What is an idempotency key? An idempotency key is a unique string sent with a write. The server uses it to recognize a retry. The server then returns the first result instead of acting a second time. **On Runtime, every write carries an idempotency key. Both SDKs create one for you and retry with it. 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 keeps 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 received it or completed it and the reply was lost. A retry without a key may start a second machine, which is 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 new process after a crash. An MCP client may repeat a tool call that it believes failed. An idempotency key turns "did that happen?" into a question that the server answers. ## How Runtime treats a key | Request | What the server does | | -------------------------------- | ---------------------------------------------------------------------------------- | | Same key, same body | Returns the first result again, with `"replayed": true` | | Same key, different body | Returns 422 `idempotency_key_reused` | | New key | Treats the request 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 final. A retry with the same key returns the same error. To try again, fork with a new key ([API](/docs/api#retries-and-idempotency)). ## Survive a process restart The key that the SDK creates lasts only as long as the call. To make a retry safe after your own process stops, derive the key from the job. The next attempt then sends the same key. This demonstration chooses a new job ID once. A restarted worker loads the saved ID from its queue, and it keeps both that ID and the input unchanged. Never choose a new job ID inside a retry loop. ```ts import { randomUUID } from "node:crypto"; import { Runtime } from "withruntime"; const runtime = new Runtime(); const job = randomUUID(); 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 ``` Send the same body on the retry. If you change the input under the same key, the request is not a retry, and the server returns an error to say so. ## Keys over MCP An agent that calls Runtime's MCP tools directly should choose and record a unique `idempotencyKey` before the first call. After a lost reply, it should reuse that key with identical input. The server generates a key for an omitted field, and that key cannot be recovered from a lost reply. Read the resource before you repeat that write ([MCP](/docs/mcp)). When a command's outcome is still unknown after a timeout, inspect its files and processes before you repeat 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 October 2026.