Skip to content
Y
YAS.SH
Developers

Why POST Needs Idempotency Keys

Prevent duplicate links and charges with a real example.

mohamed-elsaadouni8 min readapiidempotencydevelopers
Why POST Needs Idempotency Keys
Featured imageWhy POST Needs Idempotency Keys

Why POST Needs Idempotency Keys

You send a request. The server processes it. But the response is lost in the network — a timeout, a dropped connection, a flaky mobile network. So your client retries. The server processes it again. Now you have two short links, or two charges, or two emails.

This is the classic duplicate-problem, and the fix is an idempotency key: a unique string your client sends with the request so the server can recognize and deduplicate retries. This guide explains how they work, when you need them, and how to implement them on the create-links pattern.

The problem: retries are inevitable

Networks drop things. It's not a bug — it's physics. A request can succeed at the server and still "fail" for the client because the response never arrived. The client's only sane behavior is to retry. But a retry of a non-idempotent operation creates a duplicate.

  • Retrying a create → duplicate resource.
  • Retrying a charge → double charge.
  • Retrying a send → double email.

Without a way to tell "this is the same request as before," the server can't know it should return the original result rather than create another one.

What an idempotency key is

An idempotency key is a unique, client-generated string sent as a header (or body field) on a request:

POST /api/v1/links
Idempotency-Key: 4f8a9c2e-...-unique

The contract:

  1. The client generates a fresh key for each new logical operation.
  2. The same key is reused on every retry of that operation.
  3. The server stores the key with the operation's result.
  4. If a request with an already-seen key arrives, the server returns the stored result instead of running the operation again.

The key only needs to be unique per client; the server treats it as opaque.

How the server handles it

A minimal implementation:

key = request.header("Idempotency-Key")
if key is present:
    existing = store.lookup(key)
    if existing:
        return existing.result        # deduplicate — no second create
    result = create_link(payload)     # do the real work
    store.save(key, result)           # remember for retries
    return result

Two things matter:

  • Check the key before doing the work. The lookup must happen before the side effect, so a retry never triggers a second create.
  • Store the result atomically with the work, so a race between two identical requests can't both create.

Say a mobile app shortens a URL. The user taps once, the network blips, the app retries. Without a key:

  • Request 1 creates ab3x7.
  • Request 2 creates cd5y9.
  • The user now has two links for the same destination.

With an idempotency key:

  • Request 1 (Idempotency-Key: abc) creates ab3x7 and stores the result under abc.
  • Request 2 (Idempotency-Key: abc) finds the stored result and returns ab3x7.
  • The user gets one link, and the client gets a clean success.

This is exactly how a robust create-links API should behave — and why a good shortener API supports idempotency keys on its POST /links endpoint.

When you need it vs when you don't

Need it for any non-safe operation with a side effect you don't want duplicated: creating resources, charging payments, sending emails, registering, uploading.

Don't strictly need it for GET (already idempotent) or for operations you're willing to let run twice. But even "harmless" duplicates create confusion and data-quality problems, so the key pattern is cheap insurance.

Common mistakes

  1. Checking the key after the work. If you create first and check later, retries still duplicate.
  2. Reusing one key for everything. The key identifies a specific operation; reuse breaks dedup.
  3. Ignoring the key on some clients. If only some clients send keys, retries from the others still duplicate. Enforce it on the critical paths.
  4. Not storing enough to return the original result. If you don't persist the result, you can't replay it.

The takeaway

Idempotency keys turn an unsafe retry into a safe one. Generate a unique key per operation, reuse it on retries, and have the server check it before doing work and store the result. It's a small header that prevents the most embarrassing class of bugs — duplicate links, duplicate charges, duplicate emails.

When you're building on yas.sh's API, send an Idempotency-Key on link creation to guarantee your retries never create duplicates.

Frequently asked questions

What is an idempotency key?

A unique client-generated string sent with a POST request so the server can recognize and deduplicate retries. If the same key arrives again, the server returns the original result instead of creating a duplicate.

Why do I need one for creating links?

Network timeouts and client retries can resend the same create request. Without a key, you get duplicate links. With a key, the second request is a no-op that returns the first result.

When should I send an idempotency key?

Whenever the operation has a side effect you don't want duplicated: creating a resource, charging a payment, sending an email, or registering something. GET is naturally idempotent; non-safe POSTs benefit most.

Was this helpful? Share
🍪 Cookies & privacy. yas.sh uses only essential cookies to keep you signed in and remember your preferences. We do not run third-party trackers. See our cookie policy and privacy policy.
Settings