Skip to main content
Sending the same POST /v1/posts request twice should publish exactly one post per target. That’s what the Idempotency-Key header buys you — and on multi-target batches it covers every target in the batch, not just the first.

How it works

Pass a unique key — typically a UUID v4 — on every write:
header.txt
Idempotency-Key: 01HY6X4AWBJM2K9F2PTQMRD9JQ
The first request with that key executes normally. Any subsequent request with the same key, the same route, and a matching body hash returns the first response verbatim — same status code, same batch envelope, same per-target results[]. None of the underlying platform calls run a second time. If the body hash differs from the first request, you get back idempotency_conflict so you don’t accidentally publish two different posts under one key.

Multi-target batches

The key applies to the whole batch. If you send a request with targets: [A, B, C] and retry with the same key, you replay the same batch response — A, B, and C each publish at most once, even if the first call partially succeeded. Change any target (add D, remove C, swap an accountId) and the body hash changes; you’ll get idempotency_conflict on the retry.
retry-safe.sh
# First call — fans out to three targets.
curl -X POST https://api.letmepost.dev/v1/posts \
  -H "Authorization: Bearer $LMP_KEY" \
  -H "Idempotency-Key: 01HY6X4AWBJM2K9F2PTQMRD9JQ" \
  -H "Content-Type: application/json" \
  --data @- <<EOF
{
  "targets": [
    { "accountId": "<twitter_account_id>" },
    { "accountId": "<linkedin_account_id>" },
    { "accountId": "<bluesky_account_id>" }
  ],
  "text": "shipped"
}
EOF

# Network blew up before the response landed? Retry with the same key,
# byte-identical body. You get back the original batch envelope; no
# target publishes twice.

When to use a key

  • Every retry path. Network blip, lambda re-invocation, Temporal workflow restart — pin them to a key the caller computes deterministically.
  • Every webhook handler that publishes. Webhooks are at-least-once; keys make idempotent processing a one-line addition.
  • Every CI / cron job that posts on a schedule.

What counts as the “same request”

The replay cache keys on:
  • API key
  • HTTP method + path
  • The exact Idempotency-Key header
  • A SHA-256 hash of the request body
Change the body and the second request returns idempotency_conflict — that’s a feature, not a bug. It catches the case where you reused a key by mistake but actually meant to publish something different.

TTL

Replay records are kept for 24 hours after the first request, then evicted. Beyond 24h the same key is treated as fresh, so don’t rely on long-lived dedup; that’s what idempotent application logic is for.

Generating keys

UUID v4 from any standard library is fine. For deterministic retries, hash the upstream event id (e.g., your Temporal workflow run id):
key-strategies.ts
// Random per-call — fine for ad-hoc scripts.
const key = crypto.randomUUID();

// Deterministic from your own correlation id — best for workflows.
const key = sha256(\`workflow:\${workflowId}:step:\${stepName}\`);

What this is not

Idempotency keys do not deduplicate based on content. Two different keys, same body, will publish two posts. That’s the contract — the key is the unit of “this is the same request”; we don’t second-guess.

See also