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

> ## Agent Instructions
> To quote bridges and swaps, look up chains and tokens, or track Relay transactions from an agent, use the Relay MCP server: `npx -y @relayprotocol/relay-mcp`. It is read-only and does not sign or broadcast transactions. Setup: https://docs.relay.link/resources/developing-with-ai.md
> For Relay Protocol's trust model, security architecture, and audits, see https://docs.relay.link/references/protocol/security.md. For address screening, see https://docs.relay.link/security/transaction-screening.md.

# Access Tokens

> Mint short-lived tokens so browser clients can call the Relay API without exposing your API key.

An access token is a short-lived credential that your backend mints (issues) from your API key and passes to a browser or mobile client. The client sends the token to Relay, so the API key never leaves your server. Each token expires after 15 minutes.

Use the table below to choose between an access token and the other ways to call Relay from a client.

| Approach | API key location | Who calls Relay | Use it when |
| - | - | - | - |
| API key | Your server | Your server | Your integration runs server to server |
| [Proxy API](https://docs.relay.link/references/api/api-keys.md#proxy-api) | Your server | Your server, for each client request | You want every request to pass through your backend |
| Access token | Your server | The client, with a token | You want the client to call Relay directly |

## Requirements

1. **An App with elevated rate limits** — Only Apps with [elevated rate limits](https://docs.relay.link/references/api/api-keys.md#elevated-rate-limits) can mint tokens. Request them through the support widget in the [Relay Dashboard](https://dashboard.relay.link).
2. **A token endpoint on your backend** — This endpoint holds the API key, mints tokens, and returns them to your client.

## How to use it?

The flow has four steps:

1. Your backend sends your API key to [`POST /access-tokens`](https://docs.relay.link/references/api/create-access-token).
2. Your backend returns the token to the client.
3. The client sends the token in the `Authorization` header on supported Relay endpoints.
4. When the token expires, the client requests a new token from your backend.

### Mint a token on your backend

Send your API key in the **`x-api-key`** header with an empty JSON body.

```typescript theme={null}
// Route handler on your backend, for example POST /api/relay-token
export async function POST() {
  // 1. Mint a token with your API key (server-side only)
  const response = await fetch("https://api.relay.link/access-tokens", {
    method: "POST",
    headers: {
      "x-api-key": process.env.RELAY_API_KEY!,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({}),
  });
  if (!response.ok) {
    const { errorCode } = await response.json();
    return Response.json({ error: errorCode }, { status: response.status });
  }

  // 2. Return only the token and its expiry to your client
  const { token, expiresAt } = await response.json();
  return Response.json({ token, expiresAt });
}
```

The response has four fields:

| Field | Description |
| - | - |
| **token** | The token to send from the client |
| **tokenType** | Always `Bearer` |
| **expiresAt** | When the token expires, as an ISO 8601 timestamp |
| **scope** | Always `public-api` |

The response has `Cache-Control: no-store`. Do not cache it.

### Call Relay from the client

Send the token in the `Authorization` header over HTTPS.

```typescript theme={null}
// 1. Get a token from your backend, never the API key
const { token } = await fetch("/api/relay-token", { method: "POST" }).then(
  (r) => r.json()
);

// 2. Call Relay with the token
const quote = await fetch("https://api.relay.link/quote/v2", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${token}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    user: "WALLET_ADDRESS",
    originChainId: 8453,
    destinationChainId: 10,
    originCurrency: "0x0000000000000000000000000000000000000000",
    destinationCurrency: "0x0000000000000000000000000000000000000000",
    amount: "1000000000000000000",
    tradeType: "EXACT_INPUT",
  }),
});
```

Send an API key or a token in a request, not both. Relay rejects a request that has both.

## What a token can do

| Endpoint group | Allowed with a token |
| - | - |
| Quotes and prices | Yes |
| Request status | Yes |
| Request history | Yes, public data only |
| Signed execution | Yes |
| Transaction submission and indexing | Yes |
| Chain, configuration, and currency lookups | Yes |
| Fee sponsorship and fixed-rate parameters | No |
| Minting another token | No |
| Dashboard, admin, deposit address management, and all other endpoints | No |

Make requests that use fee sponsorship or fixed rates from your backend with your API key. Enforce your sponsorship rules there.

With a token, request history returns public data only. It does not include the integrator-level read access that an API key can have.

## Rate limits

Relay counts token requests for each API key and client IP address. All tokens from the same API key and the same IP share one allowance. More tokens do not increase it.

| Request type | Limit per minute |
| - | - |
| Quotes | 10 |
| Request status | 100 |
| Request history | 100 |
| Other supported endpoints | 60 |

Different IP addresses and different API keys have separate allowances. Minting is limited to 600 requests per minute for each API key. Failed mint attempts count toward that limit.

When a limit is reached, Relay returns `429` with the error code `RATE_LIMITED`. See [Handling Rate Limits](https://docs.relay.link/references/api/api_core_concepts/handling-rate-limits.md) for how to recover.

## Token lifecycle

| Event | What happens | What to do |
| - | - | - |
| The token reaches 15 minutes | Requests return `401` | Mint a new token through your backend |
| The client changes network | The token keeps working. Its rate limit counts under the new IP | Nothing |
| You deactivate the API key | All its tokens stop working after Relay's key cache refreshes | Mint tokens from an active key |
| You rotate the API key or change the App's settings | Existing tokens keep working until they expire | Nothing |
| You need to revoke one token | Relay cannot revoke a single token | Deactivate the API key to revoke all its tokens |

## Errors

The API also calls a token an API session, for example in the error code `INVALID_API_SESSION`.

| Status | Error code | Meaning | What to do |
| - | - | - | - |
| `400` | `INVALID_REQUEST_PARAMS` | The request used a parameter that tokens cannot use, for example fee sponsorship | Send that request from your backend with your API key |
| `401` | `INVALID_API_SESSION` | The token is invalid or expired, or its API key was deactivated | Mint a new token through your backend |
| `403` | `FORBIDDEN` | The API key cannot mint tokens because its App does not have elevated rate limits | Request [elevated rate limits](https://docs.relay.link/references/api/api-keys.md#elevated-rate-limits) |
| `429` | `RATE_LIMITED` | A rate limit was reached | Wait and retry |
| `500` | `API_SESSION_UNAVAILABLE` | Token minting or validation is temporarily unavailable | Retry with backoff |

## Caveats

* A token works from any origin and IP address, because Relay checks the App's IP and origin restrictions only on the mint request. Restrict your App to your backend's IP addresses.
* Protect your token endpoint against automated abuse. Anyone who can call it can get a token, so authenticate or throttle it.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.