> ## Documentation Index
> Fetch the complete documentation index at: https://developers.jobhandy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Retries, idempotency, and ambiguous outcomes

> Retry only when replay is safe and reconcile write timeouts by reading the current resource state.

The public v1 contract does not define a general idempotency-key header. `X-Request-ID` is correlation metadata only.

## Retry decision

```mermaid theme={"theme":{"light":"github-light","dark":"github-dark"}}
flowchart TD
    A[Request failed or timed out] --> B{Read or write?}
    B -- Read --> C{Transient status or network failure?}
    C -- Yes --> D[Retry with bounded backoff]
    C -- No --> E[Correct request or stop]

    B -- Write --> F{Response proves no write occurred?}
    F -- Yes --> G[Correct request or retry if safe]
    F -- No / unknown --> H[Re-read affected resource]
    H --> I{Desired state already applied?}
    I -- Yes --> J[Reconcile locally]
    I -- No --> K{Replay safe after current-state check?}
    K -- Yes --> L[Retry with a new request ID]
    K -- No --> M[Escalate for manual resolution]
```

## Retry matrix

| Situation                                       | Automatic retry | Required behavior                                                    |
| ----------------------------------------------- | --------------: | -------------------------------------------------------------------- |
| `GET` timeout or transient 5xx                  |    Usually safe | Use bounded exponential backoff and a retry budget                   |
| `429`                                           |    Yes, bounded | Honor `Retry-After` before the next attempt                          |
| `400`, `401`, `403`, `406`, `413`, `415`, `422` |              No | Correct request, credential, scope, media type, or data              |
| `409`                                           |  No blind retry | Re-read current resource and resolve the conflict                    |
| Create request timeout                          |  No blind retry | Search or reconcile before another create                            |
| Order decision timeout                          |  No blind retry | Re-read the order and compare current status                         |
| Patch timeout                                   |  No blind retry | Re-read resource fields before deciding on another patch             |
| Attachment upload timeout                       |  No blind retry | Re-read incident state and available attachment result where exposed |
| Binary download `502`/`503`/`504`               |     Conditional | Retry download with backoff; do not treat partial data as complete   |

## Backoff example

```text theme={"theme":{"light":"github-light","dark":"github-dark"}}
attempt 1: immediate
attempt 2: 1 second + jitter
attempt 3: 2 seconds + jitter
attempt 4: 4 seconds + jitter
stop when the retry budget is exhausted
```

Use `Retry-After` as the minimum delay for `429` responses.

## Reconciliation patterns

### Employee create

* Store a stable source identifier such as `employeeNumber`.
* After a timeout, search by the stable source identifier before creating again.
* Treat a duplicate response as a reconciliation signal, not as a transient failure.

### Order decision

* Read the order immediately before the decision.
* After a timeout, read it again.
* If the status already reflects the decision, record success locally.
* If the order is still eligible, decide whether a controlled replay is appropriate.

### Patch

* Read the current resource.
* Compare the fields owned by the integration.
* Patch only fields that still differ.

## Operational rule

<Warning>
  Never retry a write solely because the client did not receive a success response. A network timeout can occur after JobHandy has persisted the mutation.
</Warning>
