Idempotency and retries
An idempotency key identifies one intended mutation, including its original method, target and body. Generate it before the request, keep it through an uncertain network outcome, and reuse it only for that same operation. A fresh key after a timeout can create a second effect.
Wire behavior
- Control API:
Idempotency-Key(≤ 255 chars) is required onPOST /computers,POST /computers/{id}/snapshots,POST /images,POST /billing/topupsandPOST /api-keys, and accepted on every other control API POST and PATCH . Kept 24 h per account with the request hash and response.- Same key, different body:
409 idempotency_mismatch. Same key while the first is still running:409 idempotency_in_progress(+Retry-After). Replay: original response +Idempotent-Replayed: true. - Credentials are never stored for replay. This covers every response that contains a credential: access
tokens, preview
access_urlandcpt_tokens, hook URLs, share-link URLs, API-key and webhook secrets. A replay returns the metadata with that fieldnullandsecret_already_returned: true. The SDK and CLI then tell the user to mint, create or rotate a new one.
- Same key, different body:
- Data plane: only
POST /execandPOST /processesacceptIdempotency-Key. For 24 h from initial acceptance, the computer's agent retains the canonical request hash and{proc_id, status}metadata, scoped to computer ID and route, not output. Same key with a different request body returns409 idempotency_mismatch. Before the first request has a process record, a concurrent duplicate returns409 idempotency_in_progresswithRetry-After: 1. Once that record exists, a duplicate returns200 application/json,Idempotent-Replayed: true, and{proc_id, status}, wherestatusisrunningorexited. This replay response applies even if the original request selectedstreamorbackground; it never launches another process and never replays an NDJSON body. The supervisor updates status on exit and retains the terminal status for the rest of the deduplication window, independently of output retention. Fetch available output separately fromGET /processes/{proc_id}/output; it may have expired after the one-hour retention period. Every other data-plane POST is not idempotent; the docs and SDKs say so. - SDK retry rule: retry control API calls on 429/503 with
Retry-After. Retry data-plane calls only when the response hasCE-Not-Forwarded: true. Never retry after 502/504 or a network error once the request was sent, except keyed exec/process start with the caller's original key. - Lifecycle verbs are naturally idempotent: stopping a stopped computer returns 200 with its state.
Replay is not renewed authority
An idempotent result does not waive current authentication, scope, restriction, expiry or hold checks. Some replies contain a secret that is returned only once; a replay can identify the resource without reissuing that secret. Follow SecretAlreadyReturned and ProcessReplay as distinct recovery paths. Keyed exec replay attaches to retained process identity; it does not rerun the command to reconstruct missing output.
For asynchronous effects, retain the operation ID and poll Operations. A local waiter timeout is not a cancel signal. Check current state before choosing another action, and never alter a body under the old key merely to bypass a refusal.
Dory is in development; these pages describe the planned service and may change. Questions: support@computeengines.com.