> ## 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.

# Request expiry

> Prevent replay attacks and delayed execution with request expiry timestamps

The `privy-request-expiry` header allows your app to set a deadline for when an API request must be processed. Privy rejects requests where the expiry timestamp has passed, helping prevent replay attacks and the delayed presentation of previously signed requests.

## Required headers

When using request expiry with the REST API, include the following header with your request:

<ParamField header="privy-request-expiry" type="string">
  A Unix timestamp in milliseconds representing the deadline by which the request must be processed
  (e.g., `1773679531000`).
</ParamField>

## When is it necessary?

The `privy-request-expiry` header is optional for all endpoints where authorization signatures are accepted, but strongly recommended for:

* Requests that include [authorization signatures](/api-reference/authorization-signatures), to limit the window in which a signed request can be used
* State-changing operations where delayed execution could be problematic
* Security-sensitive operations where replay attacks are a concern

## How request expiry works

<Steps>
  <Step title="Set the expiry">
    When making a request, include the `privy-request-expiry` header with a Unix timestamp in
    milliseconds representing the deadline for the request.
  </Step>

  <Step title="Include in signature payload">
    If the request requires an [authorization signature](/api-reference/authorization-signatures),
    the `privy-request-expiry` header must be included in the [signature
    payload](/controls/authorization-keys/using-owners/sign/overview#signature-payload) under the
    `headers` field. The value signed must match the header value sent with the request.
  </Step>

  <Step title="Server-side validation">
    When Privy receives the request, it checks the `privy-request-expiry` value against the current
    server time. If the expiry timestamp is in the past, the request is rejected with a
    [`request_expired`](/basics/troubleshooting/error-handling/api-errors#request-expired) error.
  </Step>
</Steps>

<Warning>
  The expiry value must be a Unix timestamp in **milliseconds**, not seconds. Using seconds will
  result in a timestamp that appears to be far in the past, and the request will be rejected.
</Warning>

## Request expiry in Privy SDKs

<Info>
  If you are using any of Privy's SDKs below, a default expiry of 15 minutes is set if you don't
  specify one. Intents endpoints default to a 72-hour expiry instead.
</Info>

If you'd like to override the default value, you can configure the default expiry globally when constructing the client, or override it on a per-request basis:

<Tabs>
  <Tab title="Node SDK">
    ```typescript theme={"system"}
    import {PrivyClient} from '@privy-io/node';

    // Configure custom default expiries globally (in milliseconds)
    const privy = new PrivyClient({
      appId: 'your-app-id',
      appSecret: 'your-app-secret',
      requestExpiry: {
        defaultMs: 10 * 60 * 1000, // 10 minutes for standard calls
        defaultIntentMs: 24 * 60 * 60 * 1000 // 24 hours for intents endpoints
      }
    });

    const walletId = 'your-wallet-id';

    // Uses the configured default expiry (10 minutes)
    const responseWithDefaultExpiry = await privy.wallets().ethereum().signMessage(walletId, {
      message: 'Hello, world!'
    });

    // Override the expiry for a specific request
    const responseWith5MinExpiry = await privy
      .wallets()
      .ethereum()
      .signMessage(walletId, {
        message: 'Hello, world!',
        request_expiry: privy.getRequestExpiry(5 * 60 * 1000) // 5 minutes
      });
    ```
  </Tab>
</Tabs>

## Including in authorization signatures

When a request includes both a `privy-request-expiry` header and an authorization signature, the expiry must be included in the signature payload. This ensures that the expiry cannot be tampered with after signing.

```json theme={"system"}
{
  "version": 1,
  "method": "POST",
  "url": "https://auth.privy.io/api/v1/wallets/<wallet_id>/rpc",
  "body": {
    "method": "personal_sign",
    "params": {
      "message": "Hello, world!"
    }
  },
  "headers": {
    "privy-app-id": "insert-your-app-id",
    "privy-request-expiry": "1773679531000"
  }
}
```

See [authorization signatures](/api-reference/authorization-signatures) for the full signature payload specification.

## Error handling

If a request is received after its expiry timestamp, Privy returns a `request_expired` error. See the [API error codes](/basics/troubleshooting/error-handling/api-errors#request-expired) page for details and troubleshooting steps.
