---
title: "Errors and limits — Anis Developers"
description: "What every refusal carries, how to branch on it, and the limits that can apply to your application."
url: https://developers.anis.ly/docs/errors-and-limits/
language: en
---

> Every page of this documentation: https://developers.anis.ly/llms.txt

# Errors and limits

## What a refusal carries

Every refusal is a signed JSON problem:

```json
{
  "type": "https://developers.anis.ly/errors/price-changed",
  "title": "Price changed",
  "status": 409,
  "code": "price_changed",
  "requestId": "01J9R2K8T4V6XQ0M3B7C5D9E1F"
}
```

- **Branch on `code`.** Never on `title` or `detail`: they are written for people, follow the language you ask for (`Accept-Language: ar` or `en`) and can change wording.
- **`type`** is the address of the code’s page — every code has one in [Error codes](https://developers.anis.ly/errors.md), saying what it means, whether an order was bought and what to do.
- **`requestId`** is what to quote when you ask Anis about a call. It is also in the `X-Request-Id` header of every answer.

## Two things a refusal may carry

- **`Retry-After`** — when Anis knows how long to wait, in seconds. Honour it.
- **`Idempotency-Replayed: true`** — on an order: the recorded answer of an order that is already closed.

## Refusals that hide which rule failed

Some refusals give the same answer for different causes, on purpose, so that a refusal never tells anyone which thing to work around:

| Code | Covers |
| --- | --- |
| [`invalid_credentials`](https://developers.anis.ly/errors/invalid-credentials.md) | an unknown key, a key that is not active, a revoked key, a wrong signature, an expired signature, a body that does not match its digest |
| [`insufficient_scope`](https://developers.anis.ly/errors/insufficient-scope.md) | a missing permission, or a call from outside your allowed networks |
| [`wallet_not_granted`](https://developers.anis.ly/errors/wallet-not-granted.md), [`resource_not_found`](https://developers.anis.ly/errors/resource-not-found.md) | something that does not exist, or that is not yours |
| [`validation_failed`](https://developers.anis.ly/errors/validation-failed.md) | any broken rule — the field is never named |

## Limits

Anis staff can set limits on your application, for the whole application or per wallet. Each counts one kind of call in a time window:

| Limit | Counts |
| --- | --- |
| All requests | every signed call |
| Orders | placing an order (and resuming one) |
| Reveals | both reveals |

When a limit is reached the call is refused as [`rate_limited`](https://developers.anis.ly/errors/rate-limited.md), with `Retry-After` when the reset time is known. Anis also protects itself with limits that give no reset time — back off exponentially then. A refused call records nothing: once the wait is over, send it again (an order keeps its operation id).

The [Routes and permissions](https://developers.anis.ly/docs/routes-and-permissions.md) page shows which limits each call counts toward.

> **Spending limits are different**
>
> [`owner_limit_exceeded`](https://developers.anis.ly/errors/owner-limit-exceeded.md) and [`daily_limit_exceeded`](https://developers.anis.ly/errors/daily-limit-exceeded.md) are limits on what the Anis business account may spend, not on how often you call. Waiting does not reset them — do not retry in a loop.
