# Idempotency and recovery

Save an idempotency key with each intended API execution. If a response is lost, the same key and request identify the original work and allow a delivered result to be replayed.

Customer workspace calls to `POST /v1/sources/{source_id}/run` and `/stream` require the `Idempotency-Key` header. These rules describe those execution endpoints; builds, key creation, checkout, and other operations have their own contracts.

## Save the request before sending

Use a UUID or another unique string containing 1–200 letters, numbers, periods, underscores, colons, or hyphens. Save it in your job record together with:

- The workspace and source identifier.
- The full definition version.
- The execution endpoint: `/run` or `/stream`.
- The exact input values.

For the documentation examples, load this saved value into `CLEANEDWEB_IDEMPOTENCY_KEY`. Keep it stable across an interrupted attempt. Generating a new key every time a retry function runs creates new work.

```http
Idempotency-Key: 72ad1b16-20ad-4ef4-a578-d8b893601d7e
```

This key is illustrative. Generate your own for a new execution. The connection details supplied by the console also include an example key. Fetching those details again creates a new example key, so retain the one you actually used.

## What a key identifies

Within an authenticated workspace, a key binds the source, resolved definition version, input, and execution surface. Object property order does not create a new identity. Changing a limit, adding an input, selecting another version, or switching from `/run` to `/stream` changes the request.

| Situation | Behavior |
| --- | --- |
| New key and valid request | Starts a new execution. |
| Same key and same request, result delivered | Returns the retained result and its delivery receipt without another collection or debit. |
| Same key, execution output saved but delivery unsettled | Attempts settlement of the saved output; source collection is not repeated. |
| Same key, request still running or recorded as failed | Returns `409` with `result_already_running_or_failed`; it does not restart the execution. |
| Same key with a changed request | Returns `409` with `delivery_identity_conflict`. |
| Missing or invalid key | Returns `422` with `idempotency_key_required`. |

An `expected_version` check still applies before replay. If the active definition has changed, a request can return a version conflict. Preserve the original identity and use recorded run details or support to resolve it; do not silently update the version on the saved request.

## Recover a lost response

1. Keep the original key, source, version, endpoint, and inputs. A timeout does not tell you whether execution completed.
2. If you retained `delivery.runId`, read `GET /v1/sources/{source_id}/runs/{run_id}/result` using a credential with `results` access. This retrieves the existing delivery.
3. If the run identifier is unavailable, resubmit the same execution request with the original key. A delivered result is replayed; pending or failed work can return a conflict.
4. Respect `Retry-After` where supplied. A `result_already_running_or_failed` conflict does not distinguish a slow run from a failed one. Inspect the workspace's recorded run before deciding to wait, request help, or start a new execution.
5. Validate the recovered response's version, records, and summary as you would the initial response.

Use a bounded recovery policy and stop when the state remains uncertain. Do not generate replacement keys in a loop. A new key can execute the source again and create new usage.

## Keep delivery evidence

Store `delivery.runId`, `delivery.chargeReceiptId`, and `delivery.recordCount` with the request identity and output. The charge receipt identifies a delivered execution charge; it is separate from a credit-purchase receipt or invoice.

For review, provide the source identifier, definition version, run and trace identifiers, error code, and request timing. Never share API credentials. See [errors and retries](/docs/errors/) and [Run an API](/docs/run-api/).
