> ## Documentation Index
> Fetch the complete documentation index at: https://phone-harness.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Retries and idempotency

> Recover a lost creation response without allocating another phone.

## One key per logical Start

Send an `Idempotency-Key` header with `POST /sessions`. Use 16–128 ASCII letters, digits, underscores, or hyphens. A UUID is a suitable value.

The key belongs to your account. Replaying the same key with the same parsed JSON body returns the existing session identity instead of allocating another phone. JSON key ordering does not matter; changing fields or adding a formerly omitted default does.

```bash theme={null}
curl --fail-with-body -sS https://api.phone-harness.com/sessions \
  -H "Authorization: Bearer $PHONE_HARNESS_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $REQUEST_KEY" \
  -d '{"timeout_seconds":900}'
```

Without this header, each accepted POST can create another session.

## Recover an ambiguous result

If your connection drops after sending the request, you may not know whether a phone was created. Look up the key:

```bash theme={null}
curl --fail-with-body -sS \
  "https://api.phone-harness.com/sessions/requests/$REQUEST_KEY" \
  -H "Authorization: Bearer $PHONE_HARNESS_API_KEY"
```

```json Illustrative response theme={null}
{
  "id": "examplephone",
  "request_key": "example-request-key-0001",
  "provider": "shlut",
  "state": "provisioning",
  "cleanup_complete": false,
  "cleanup_pending": false
}
```

Use the returned `id` to continue polling. If no receipt is found, retry the original POST with the **same key and body**. Even if the earlier request arrives late, the key prevents a second allocation for that logical request.

Do not immediately generate another key because a request timed out.

## Creation replay responses

| Response                          | Meaning                                                                                                                                                                                         |
| --------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `202`                             | The original session is returned. It may still be provisioning or closing.                                                                                                                      |
| `409`, `idempotency_conflict`     | This key was already used with a different request body.                                                                                                                                        |
| `410`, `create_request_completed` | That session has completed cleanup. Use a new key only when you intend to create another phone.                                                                                                 |
| `503`, `create_request_recorded`  | Admission was recorded, but the runtime is currently unavailable. Preserve the returned ID and recover the receipt; do not assume nothing was created.                                          |
| `503`, `phones_busy`              | Every phone is in use. Nothing was created and nothing is billed. Wait `retry_after_seconds` (also the `Retry-After` header) and send the same request again; the same idempotency key is fine. |

The receipt remains available after the live session is removed. `state: "recorded"` is a receipt state, not API readiness. `state: "released"` and `cleanup_complete: true` confirm completed cleanup.

## Operations are different

There is no general idempotency key for taps, text entry, app launches, or APK installation. A network failure does not prove the operation did not happen. Check the phone's current state before repeating an action that could have side effects.

For read-only polling, use bounded retries with backoff. If creation is refused for capacity, wait before retrying; repeatedly issuing new creation keys does not reserve future capacity.
