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

# API rate limits

> 25 requests per second per API key, the headers that track it, and how to back off.

Each API key can make **25 requests per second**. Bulk endpoints count as one request, however many ids they carry.

Your codeAPI keyTolt25 req/s*1*GET /v2/partners (26th/s)*2*429 Retry-After: 1*3*wait 1s*4*GET /v2/partners*5*200 X-RateLimit-Remaining: 24

## Headers

| Header | Meaning |
| - | - |
| `X-RateLimit-Limit` | Requests allowed in the current window |
| `X-RateLimit-Remaining` | Requests left in the current window |
| `X-RateLimit-Reset` | Unix time, in seconds, when the window resets |
| `Retry-After` | On `429` only: seconds to wait before retrying |

Over the limit, you get `429`:

```json theme={"system"}
{
  "success": false,
  "message": "Too many requests. Retry after the window resets.",
  "code": "rate_limited",
  "doc_url": "https://docs.tolt.com/errors#rate_limited"
}
```

## Back off and retry

The SDKs already retry twice, waiting for `Retry-After`: TypeScript on `408`, `429` and `5xx`; Python on `408`, `409`, `429`, `5xx` and connection errors. Raise `maxRetries` (TypeScript) or `max_retries` (Python) if you need more. With plain HTTP, wait yourself:

```ts TypeScript theme={"system"}
async function toltFetch(
  path: string,
  init: RequestInit = {},
  attempt = 0,
): Promise<Response> {
  const res = await fetch(`https://platform.tolt.com/v2${path}`, {
    ...init,
    headers: {
      ...init.headers,
      Authorization: `Bearer ${process.env.TOLT_API_KEY}`,
    },
  });
  if (res.status !== 429 || attempt >= 4) return res;

  const seconds = Number(res.headers.get("Retry-After") ?? 2 ** attempt);
  await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
  return toltFetch(path, init, attempt + 1);
}
```

> [!WARNING]
>
> `POST /v2/transactions` has no idempotency key, but a `charge_id` acts as one per customer: retrying a request that carries one is safe, because a transaction that was already created comes back as `409 already_exists`. Without a `charge_id`, a `429` is still safe to retry (nothing was written), but a timeout or `5xx` may have created the transaction, so check with `GET /v2/transactions?customer_id=...` before retrying and turn off SDK retries for this call: `{ maxRetries: 0 }` in TypeScript, `request_options={"max_retries": 0}` in Python.

## Stay under the limit

* Page with `limit=100` instead of many small pages.
* Use bulk endpoints (`/bulk/approve`, `/bulk/decline`, `/bulk/reject`) for up to 100 ids per call.
* Use [webhooks](https://docs.tolt.com/webhooks/introduction.md) instead of polling.
* Watch `X-RateLimit-Remaining` and slow down before it hits zero.

Need more? Email [support@tolt.io](mailto:support@tolt.io).


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