> ## Documentation Index
> Fetch the complete documentation index at: https://docs.privy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Idempotency keys

> Making Privy API requests idempotent with idempotency keys

Idempotency keys prevent duplicate execution of API requests. Privy processes a request with a given idempotency key only once within a 24-hour window, preventing duplicated transactions.

## Required headers

Include the following header with REST API requests:

<ParamField header="privy-idempotency-key" type="string" required>
  A unique identifier for the request, up to 256 characters. Privy recommends V4 UUIDs.
</ParamField>

## When to use them

Use idempotency keys for:

* Any `POST` request that triggers state changes or transactions
* Scenarios where network issues might cause request retries
* Critical operations where duplicate execution would cause problems

Privy treats idempotency keys as optional, but apps should include them for all state-changing operations in production.

## How idempotency works

<Steps>
  <Step title="First request">
    Privy receives a request with a new idempotency key. It processes the request normally and stores
    both the request details and response for 24 hours.
  </Step>

  <Step title="Subsequent requests">
    The app sends another request with the same idempotency key within 24 hours:

    * **Matching body:** Privy returns the stored response without re-executing the operation
    * **Different body:** Privy returns a 400 error indicating invalid use of the key
  </Step>

  <Step title="Key expiration">
    After 24 hours, idempotency keys expire. Privy processes requests with an expired key as new
    requests.
  </Step>
</Steps>

<Warning>
  Changing any part of the request body while reusing an idempotency key results in an error. Each
  unique operation requires its own idempotency key.
</Warning>

## Error replay behavior

Replay behavior varies by endpoint group:

| Endpoint group     | Endpoints                         | 4xx replay | 5xx replay              |
| ------------------ | --------------------------------- | ---------- | ----------------------- |
| **Wallet actions** | `/transfer`, `/swap`, `/earn`     | Cached     | Deleted (retry allowed) |
| **RPC**            | `/rpc` (all chains)               | Cached     | Cached                  |
| **Import**         | `/wallets/import/init`, `/submit` | Cached     | Cached                  |
| **Wallet create**  | `/wallets`                        | Cached     | Cached                  |

<Warning>
  For RPC, import, and wallet create endpoints, Privy permanently caches a 5xx response against the
  idempotency key for its 24-hour lifetime. Generate a new key to retry after a server error.
</Warning>

<Info>
  **Policy violation exception:** If any endpoint returns a `POLICY_VIOLATION` error, Privy deletes
  the idempotency record regardless of status code. The app can retry with the same key after
  resolving the policy issue.
</Info>

## Generating idempotency keys

Generate a unique, random string for each distinct operation. Use V4 UUIDs for best results.

<CodeGroup>
  ```ts JavaScript/TypeScript theme={"system"}
  import {v4 as uuidv4} from 'uuid';

  // Generate idempotency key
  const idempotencyKey = uuidv4();
  ```
</CodeGroup>

## Examples

<CodeGroup>
  ```ts @privy-io/node theme={"system"}
  import {PrivyClient} from '@privy-io/node';
  import {v4 as uuidv4} from 'uuid';

  const client = new PrivyClient({appId: '$PRIVY_APP_ID', appSecret: '$PRIVY_APP_SECRET'});

  // Generate idempotency key
  const idempotencyKey = uuidv4();

  const res = await client
    .wallets()
    .ethereum()
    .sendTransaction('$WALLET_ID', {
      idempotency_key: idempotencyKey,
      caip2: 'eip155:8453',
      params: {
        transaction: {
          to: '0xE3070d3e4309afA3bC9a6b057685743CF42da77C',
          value: '0x2386F26FC10000',
          chain_id: 8453
        }
      }
    });
  ```

  ```ts TypeScript/JavaScript theme={"system"}
  import axios from 'axios';
  import {v4 as uuidv4} from 'uuid';

  // Generate idempotency key
  const idempotencyKey = uuidv4();

  const response = await axios.post(
    'https://auth.privy.io/api/v1/wallets/y5ofctvacjiv53u4hmnqi0e5/rpc',
    {
      caip2: 'eip155:8453',
      method: 'eth_sendTransaction',
      params: {
        transaction: {
          to: '0xE3070d3e4309afA3bC9a6b057685743CF42da77C',
          value: '0x2386F26FC10000',
          chainId: 8453
        }
      }
    },
    {
      headers: {
        'privy-app-id': 'insert-your-app-id',
        'privy-idempotency-key': idempotencyKey,
        Authorization: 'Bearer insert-your-api-key'
      }
    }
  );
  ```
</CodeGroup>

<Tip>
  Store the idempotency key alongside transaction records for critical operations. Retry behavior
  differs by endpoint. See [error replay behavior](#error-replay-behavior) to determine when to
  generate a new key.
</Tip>
