# Idempotenz

> Wie der Header Idempotency-Key Wiederholungen von POST und PATCH sicher macht: was gespeichert wird, wie lange, und welches 409 du bekommst, wenn ein Schlüssel mit anderem Body wiederverwendet wird.

Source: https://upfour.io/de/docs/api/idempotency

Sende bei einem `POST` oder `PATCH` einen `Idempotency-Key` mit. Bricht die Verbindung ab und du schickst dieselbe Anfrage noch einmal, gibt up4 die erste Antwort zurück, statt einen zweiten Monitor anzulegen.

## Den Header nutzen

```
KEY=$(uuidgen)

curl -si -X POST https://app.upfour.io/v1/monitors \
  -H "Authorization: Bearer $UP4_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $KEY" \
  -d '{"name":"Example","url":"https://example.com","monitor_type":"http"}' \
  | grep -i -E '^(HTTP|idempotency-status)'
```

```
HTTP/2 201
idempotency-status: stored
```

Führe denselben Befehl mit demselben `KEY` noch einmal aus:

```
HTTP/2 201
idempotency-status: replayed
```

## Die Regeln

| Thema | Verhalten |
| --- | --- |
| **Header** | `Idempotency-Key`, ein beliebiger nicht leerer Text. Eine UUID ist eine gute Wahl. Ein leerer oder fehlender Header schaltet die Funktion für diese Anfrage ab. |
| **Methoden** | `POST` und `PATCH`. `PUT`, `DELETE` und `GET` ignorieren den Header. |
| **Nicht erfasst** | `POST /monitors/batch` nutzt diese Schicht nicht. Es verlangt den Header und führt eine eigene Quittung (gleicher Schlüssel und Body: die gespeicherte Quittung, anderer Body: eine Ablehnung). |
| **Pflicht** | `POST /incidents/{incidentID}/escalate` und `POST /escalation-policies/{policyID}/test` antworten ohne den Header mit `400` und nehmen höchstens 128 Zeichen an. Überall sonst ist er freiwillig und ohne Längengrenze. |
| **Ein Schlüssel gehört zu** | Deinem Unternehmen, deinem Benutzer, Methode und Pfad der Anfrage (ohne Query-String) und dem Text des Schlüssels. Derselbe Schlüssel auf einem anderen Pfad ist ein anderer Schlüssel. |
| **Vergleich des Body** | JSON-Bodys werden als JSON verglichen, Leerraum und Reihenfolge der Schlüssel spielen also keine Rolle. Andere Bodys werden Byte für Byte verglichen. |
| **Gespeichert für** | 24 Stunden nach der ersten Antwort, danach wird die Quittung gelöscht. Der Schlüssel ist dann wieder frei: Die nächste Anfrage damit läuft, und ihre Antwort wird neu gespeichert. |
| **Was gespeichert wird** | Antworten mit Status 200 bis 499 und JSON-Body, auch Validierungsfehler. Nicht gespeichert werden 5xx und Antworten ohne Body. |
| **Secrets** | Die Antwort wird so gespeichert, wie sie gesendet wurde. Eine Wiederholung von `POST /webhook-subscriptions` oder `POST /webhook-subscriptions/{id}/rotate-secret` enthält deshalb innerhalb dieser 24 Stunden dasselbe einmalige `secret`, auch wenn eine spätere Rotation es ungültig gemacht hat. Siehe [Signier-Secret abrufen](https://upfour.io/docs/api/webhooks#secret). |
| **Wiederholungen** | Liefern gespeicherten Status, Content-Type und Body mit `Idempotency-Status: replayed`. |
| **Ratenlimits** | Eine Wiederholung zählt als Anfrage. |

## Was du bekommst

| Situation | Ergebnis |
| --- | --- |
| Keine Quittung zum Schlüssel | Die Anfrage läuft. Eine Antwort mit Status 200 bis 499 und JSON-Body wird gespeichert und trägt Idempotency-Status: stored. |
| Quittung, gleicher Body | Gespeicherter Status und Body kommen mit Idempotency-Status: replayed zurück. Die Anfrage läuft nicht noch einmal. |
| Quittung, anderer Body | 409 idempotency_key_conflict. details.original_request_at nennt den Zeitpunkt der ersten Anfrage. |
| Quittung, aber mit einem anderen API-Schlüssel oder unter geändertem Zugriff entstanden | 409 idempotency_replay_unavailable. Die Anfrage läuft nicht noch einmal. |
| Antwort war 5xx, 204 oder hatte keinen JSON-Body | Nichts wird gespeichert. Ein neuer Versuch mit demselben Schlüssel führt die Anfrage erneut aus. |

```json
{
  "error": {
    "code": "idempotency_key_conflict",
    "message": "Idempotency key was already used with a different request body",
    "request_id": "req_…",
    "details": { "original_request_at": "2026-10-27T09:14:02Z" }
  }
}
```

Die Quittung merkt sich, wer die Anfrage gesendet hat: den API-Schlüssel, seine Scopes und seine Zugriffsstufe sowie seinen Zugriff auf Kunden. Ein neuer Versuch mit einem anderen Schlüssel oder nachdem sich eines davon geändert hat, bekommt [idempotency_replay_unavailable](https://upfour.io/docs/api/errors#code-idempotency_replay_unavailable) statt einer Wiederholung, und die Anfrage läuft nicht noch einmal. Schau dir die Ressource an, um zu sehen, was passiert ist.

## Typische Fehler

- **Bei jedem neuen Versuch ein neuer Schlüssel.** Erzeuge den Schlüssel einmal pro gewünschter Operation und verwende ihn für jeden Versuch dieser Operation weiter.
- **Ein Schlüssel für verschiedene Operationen.** Der zweite Body bekommt [409 idempotency_key_conflict](https://upfour.io/docs/api/errors#code-idempotency_key_conflict). Nimm einen Schlüssel pro Operation.
- **Eine abgelehnte Anfrage unter demselben Schlüssel korrigieren.** Auch ein `400` wird gespeichert. Sendest du denselben Body erneut, kommt das `400` noch einmal; sendest du einen korrigierten Body, ist das ein Konflikt. Nimm für die korrigierte Anfrage einen neuen Schlüssel.
- **Wiederholen, während die erste Anfrage noch läuft.** Die Quittung wird geschrieben, wenn die erste Anfrage fertig ist, eine überlappende Wiederholung wird also nicht sicher abgefangen. Warte auf die Antwort oder dein Timeout.
- **Für den neuen Versuch einen anderen API-Schlüssel nehmen.** Siehe `idempotency_replay_unavailable` oben.
- **Sich bei `DELETE` oder `PUT` darauf verlassen.** Der Header wird bei diesen Methoden ignoriert.
