Skip to content

Stripe API errorStripe: “Keys for idempotent requests can only be used with the same parameters” and idempotency_key_in_use

A Stripe call fails with an idempotency error. Either the key was used before with different parameters, or another request with the same key is still running (idempotency_key_in_use). An idempotency key means “this exact request”, so it has to be unique per operation and reused only for a retry of that same operation.

Short answer

Generate a new key for each distinct operation, for example a random UUID created when the person presses Pay, and keep it only for retries of that call. If you derive the key from an order or cart ID, it must change whenever the amount or items change. Stop double submits, and retry with the same key and the same parameters only after the first request has finished.

Why Stripe rejects the key, and the fix

  1. 01

    The key was reused with different parameters

    “The idempotency layer compares incoming parameters to those of the original request and errors if they’re not the same to prevent accidental misuse.” Stripe, Idempotent requests

    Keys built from a cart, order or user ID repeat when the amount or items change, so the second request no longer matches the first. Create one key per operation, for example per Pay click, and reuse it only for retries of that identical request. If the amount or items change, that is a new operation and needs a new key.

    import { randomUUID } from 'node:crypto';
    
    const key = randomUUID(); // once per Pay click, reused only for retries
    const pi = await stripe.paymentIntents.create(
      { amount, currency: 'usd', customer },
      { idempotencyKey: key },
    );
  2. 02

    One key used for two different calls

    Using the same key for creating a customer and then a PaymentIntent can fail too. Give each call its own key, for example by adding the operation name to it.

  3. 03

    Two requests with the key ran at the same time

    “The idempotency key provided is currently being used in another request. This occurs if your integration is making duplicate requests simultaneously.” Stripe, Error codes (idempotency_key_in_use)

    A double click, a form that submits twice, or your own retry firing while the first call is still running sends the same key twice at once. Disable the button while the request runs and retry only after the first one returns.

  4. 04

    Retrying with the old key after changing the request

    “Retrying a cached `400` response with the same key returns the same error.” Stripe, Low-level error handling

    Once a call starts running, Stripe saves its result under the key, errors included. Retrying a declined payment with a new card or amount but the old key returns the old result or the parameters error. A changed request needs a new key.

  5. 05

    Retrying the right way

    “Retry with the same idempotency key and parameters within the first 24 hours after the original request.” Stripe, Low-level error handling

    After a network error you do not know whether Stripe ran the request. Retry with the same key and the same parameters. If you write your own retry loop, generate the key once before the loop and send it on every attempt. Stripe SDKs can also generate keys and retry automatically; the defaults depend on the SDK and version.

Checked against the vendor’s docs on : Stripe API: Idempotent requests; Stripe docs: Low-level error handling; Stripe docs: Error codes.

Rather hand it over?

Fixed scope, fixed price, paid upfront. The work happens in writing; no call needed.

Related: Stripe PaymentIntent already succeeded · Stripe webhook returns 200 but the database is not updated · Stripe “Received unknown parameter” · Stripe Invalid API Key provided

Questions

More on this error

Should I send an idempotency key on GET requests?

No. Stripe says keys on GET and DELETE requests have no effect, because those requests are idempotent already. Use them on POST requests.

How long does Stripe remember a key?

For API v1, keys can be removed once they are at least 24 hours old, so retry within that window.

Can you fix it for me?

If one bug is the whole problem, the App Fix Ticket covers it: a written diagnosis first, then the fix. If the app has more going on, the Launch Check is a written check of the whole app. Each issue found is rated critical, high, medium or low, with where it is and how it was confirmed. No issues worth fixing, no charge. If the Launch Check finds nothing rated medium or higher, Simon refunds the full $450. You keep the report either way. This applies to the first 10 Launch Checks bought after October 30, 2026.

A different error?

Describe it and get a written quote

Send the error and what you were doing. You get a written scope, a fixed price and a timeline; Simon replies by email, usually within one business day.