# Idempotency

> Send an Idempotency-Key with your POSTs. If the request is replayed (timeout, CI rerun), Rustine returns the first answer instead of doing the action again.

The network drops, a CI job is rerun, your script times out: you do not know whether the action happened. With an idempotency key, you can send the same request again safely.

## How

Add the `Idempotency-Key` header to your `POST` requests, with a value unique to the action (1 to 255 printable characters): your deploy id, your job id, or a UUID.

```http
Idempotency-Key: deploy-4f9c2e1
```

- **Same key, same request, within 24 hours**: Rustine returns the first answer, with the `Idempotent-Replayed: true` header. Nothing is done again, nothing is charged twice.
- **Same key, another request** (method, path or body): `409 idempotency_conflict`. A new action takes a new key.
- **Same key while the first request is still running**: `409 idempotency_in_progress`. Retry in a moment.
- A malformed key: `400 idempotency_key_invalid`.

`GET` requests and the `PATCH` of an issue already have no double effect: no key needed.

## Where it matters most

- **Unlocking a fix**: replaying it never uses two fixes.
- **Starting a scan** from CI: a rerun job does not start a second scan. (Even without a key, a scan of the same kind on the same site within the hour returns the recent result, with `reused: true`.)
- **Creating a project or adding a site**: no duplicate if the first answer got lost.
- **After a `500` or a `503`**: send the same request again with the same key.

## Examples

### curl

```bash
curl -i https://api.rustine.io/v1/issues/a3c5e7f9-1b2d-4c6e-8f0a-2b4d6f8a1c3e/fix \
  -X POST \
  -H "Authorization: Bearer $RUSTINE_API_KEY" \
  -H "Idempotency-Key: fix-$GITHUB_RUN_ID"
```

### Response: 200 OK (replayed)

```http
HTTP/1.1 200 OK
Idempotent-Replayed: true

{
  "object": "fix",
  "issue_id": "a3c5e7f9-1b2d-4c6e-8f0a-2b4d6f8a1c3e",
  "charged": true,
  "fixes_left": 82
}
```
