Developers · Core concepts

Idempotency and retries

Make every write safe to retry with the Idempotency-Key header, and retry the right failures with the right backoff.

Version
v1.0.0
Base URL
https://dppapi-production.up.railway.app/v1
Format
JSON · OpenAPI 3.1
FeedbackLast updated

Bu makale İngilizce olarak mevcuttur.

On this pageThe Idempotency-Key header

Networks fail in the worst place: after the server has done the work and before you hear about it. An idempotency key makes the retry return the original answer instead of doing the work twice.

The Idempotency-Key header

  • Send Idempotency-Key: <unique string> on any POST or PATCH. A UUID v4 is ideal.
  • The first response — success or error — is stored for 24 hours against your API key and that key.
  • A retry with the same key and the same request (method, path and body) gets the stored response back — same status, same body — with the header Idempotent-Replayed: true. Nothing is executed a second time.
  • The same key for a different request is refused with 422 and idempotency_key_reused.
  • While the first request is still running, a concurrent retry with its key gets 409 idempotency_in_progress: wait briefly and retry.
  • A 5xx is never stored, so retrying after a server error really runs the request again. A 4xx is stored like any other answer.
  • Keys are 1–255 characters (otherwise 400 invalid_idempotency_key) and scoped to the API key that sent them, so two integrations cannot collide.
  • Dry runs are answered before idempotency is consulted: they are never stored or replayed.
A retry-safe batch
curl -X POST "https://dppapi-production.up.railway.app/v1/items/batch" \-H "Authorization: Bearer $DPP_API_KEY" \-H "Content-Type: application/json" \-H "Idempotency-Key: 7b3e0c52-1f7d-4b8a-9a52-2f0e6d1c9a44" \-d '{"modelId": "cm1q8x2k40003l70f9a8s7d6e","count": 100,"serialPrefix": "C48-2027-","placeOfManufacture": "Stuttgart, Germany"}'
422 · same key, different body
{"error": "idempotency_key_reused","request_id": "3f1c2a9e-8d4b-4c6f-9e2a-7b5d1c0e8f34"}

Choosing keys

Derive the key from the operation, not the attempt. Generate it once when the work is decided and keep it with the job, so a retry after a crash reuses it. Good keys are a UUID stored with the job, or a natural id: batch-<ERP order>-<line>, publish-<lot>-2027-01-15.

What to retry

OutcomeRetry?How
Network error, timeoutYesSame request, same idempotency key.
429YesAfter retry-after seconds.
500, 502, 503, 504YesExponential backoff with jitter, same key.
409 idempotency_in_progressYesAfter a short wait, same key.
409 organisation_frozenNoContact us; the organisation is read-only.
400, 401, 403, 404, 422NoThe request itself must change.
207Only the failed rowsFix and resend just those, with a new key.

A retry helper

import { randomUUID } from 'node:crypto';const RETRYABLE = new Set([429, 500, 502, 503, 504]);/** POST with one idempotency key across every attempt, backing off between them. */async function postWithRetry(url, body, { attempts = 5 } = {}) {const key = randomUUID(); // one key for the logical operation, not per attemptfor (let attempt = 1; ; attempt++) {let res;try {res = await fetch(url, {method: 'POST',headers: {Authorization: `Bearer ${process.env.DPP_API_KEY}`,'Content-Type': 'application/json','Idempotency-Key': key,},body: JSON.stringify(body),});} catch (networkError) {if (attempt >= attempts) throw networkError;}if (res && !RETRYABLE.has(res.status)) return res;if (attempt >= attempts) return res;const retryAfter = Number(res?.headers.get('retry-after'));const backoff = retryAfter > 0 ? retryAfter * 1000 : Math.min(30_000, 2 ** attempt * 250) * (0.5 + Math.random());await new Promise((r) => setTimeout(r, backoff));}}

Naturally idempotent operations

  • Publishing an already-published passport returns it unchanged (bulk publish reports alreadyPublished).
  • PATCH /models/{id} with the same fields leaves the same values.
  • Recording an event is not naturally idempotent — the same reading sent twice is two events. Use a key.

Çerez tercihleri

Hangi çerezlerin kullanılacağını siz seçersiniz. Tercihinizi istediğiniz zaman alt bilgideki “Çerez ayarları”ndan değiştirebilirsiniz. Gizlilik politikası

Gerekli

Her zaman açık

Sitenin çalışması için gereklidir: açık/koyu tema seçiminiz ve bu çerez tercihiniz tarayıcınızda saklanır. Sizi izlemek için kullanılmazlar.

Analitik

Google Analytics 4, sayfaların nasıl kullanıldığını istatistiklerle ölçer ve siteyi iyileştirmemize yardımcı olur. Kabul ederseniz çerez bırakır ve ziyaretinizi tam olarak ölçer. Reddederseniz çerez bırakmaz, ancak Google yine de görüntülenen sayfa, tarayıcı türü ve IP adresi gibi teknik veriler alabilir.

_ga, _ga_* · en çok 2 yıl · Google