> Adsly docs index: https://adsly.pro/docs/llms.txt · every page in one file: https://adsly.pro/docs/llms-full.txt · OpenAPI: https://adsly.pro/docs/api/openapi.yaml

# Errors

The error format, every error code the API returns, what each means and what to do about it.

## Format

Every error has the same shape:

```json
{
  "success": false,
  "error": "cpm must be greater than 0",
  "code": "VALIDATION_ERROR",
  "param": "campaigns[2].cpm",
  "request_id": "6f1c2a7e-3b0e-4f39-9a52-0c8d7f1e2b44"
}
```

| Field | Always | Meaning |
|---|---|---|
| `error` | yes | A sentence a person can read. Show it; don't parse it — wording can improve. |
| `code` | yes on all v1 errors | Stable, machine-readable. Branch on this. |
| `param` | on input errors | The field that was wrong, as a path: `cpm`, `campaigns[2].channels[0]`, `account_id`. |
| `request_id` | on most errors | Same as the `X-Request-Id` response header. Quote it to support. |

Some errors add context: `min_cpm` and `currency` when Telegram refuses a bid as too low, `missing` with `UNKNOWN_AD_IDS`, `limit` with `QUEUE_FULL`.

## HTTP status codes

| Status | Meaning | Retry? |
|---|---|---|
| 200 | Done | — |
| 202 | Accepted, running in the background — poll the [task](https://adsly.pro/docs/api/tasks.md) | — |
| 400 | The request is wrong (field, value, missing `account_id`) — or Telegram refused the change | No — fix the request |
| 401 | No key, bad key, or the key reaches no cabinet | No |
| 403 | The key or plan isn't allowed to do this | No |
| 404 | Not found among the cabinets this key reaches | No |
| 409 | Conflict with the current state (cabinet locked, Telegram session expired, same request in progress) | Sometimes — see the code |
| 413 | File too large | No |
| 422 | `Idempotency-Key` reused for a different request | No — use a new key |
| 429 | Rate limit or queue full | Yes, after `Retry-After` seconds |
| 500 | Our bug — already logged | Read the state first, then retry with backoff |
| 503 | Temporarily unavailable | Yes, after `Retry-After` |

## Codes

### Authentication and access

| Code | HTTP | What to do |
|---|---|---|
| `API_KEY_MISSING` | 401 | Send `X-API-Key`. |
| `API_KEY_INVALID` | 401 | The key is wrong, revoked or expired. Create a new one. |
| `NO_ACCOUNTS` | 401 | The key reaches no active cabinet right now (cabinet deactivated, access removed). |
| `FORBIDDEN` | 403 | This key type isn't allowed for its owner. |
| `READ_ONLY_KEY` | 403 | Turn on **Manage campaigns** for the key in the panel. |
| `WRITE_NOT_ALLOWED` | 403 | This key type (issued by Adsly for partners) never writes. |
| `VIEW_ONLY_ACCESS` | 403 | Your access to this cabinet is Viewer. Ask the agency owner for Manager. |
| `FEATURE_NOT_AVAILABLE` | 403 | The plan doesn't include this action (the response names the `feature`). |
| `SUBSCRIPTION_REQUIRED` | 403 | The cabinet's owner has no active subscription. |
| `ACCOUNT_INACTIVE` | 403 | The cabinet is deactivated. |

### Finding things

| Code | HTTP | What to do |
|---|---|---|
| `ACCOUNT_ID_REQUIRED` | 400 | The key reaches several cabinets (or this `ad_id` exists in several) — pass `account_id`. |
| `ACCOUNT_NOT_FOUND` | 404 | That `account_id` isn't reachable with this key. Check `GET /v1/account/info`. |
| `CAMPAIGN_NOT_FOUND` | 404 | No such campaign in the key's cabinets (or it is deleted). |
| `TASK_NOT_FOUND` | 404 | No such task for this key's owner. |
| `NOT_FOUND` | 404 | No stats for this campaign and period. |
| `UNKNOWN_AD_IDS` | 400 | Some `ad_ids` in a bulk call aren't campaigns of that cabinet; `missing` lists them. |

### Input

| Code | HTTP | What to do |
|---|---|---|
| `VALIDATION_ERROR` | 400 | `param` names the field; `error` says what's wrong. Unknown fields are rejected too — check spelling. |
| `UNSUPPORTED_MEDIA` | 400 | Upload JPG, PNG, GIF, WEBP or MP4 in the `file` field. |
| `FILE_TOO_LARGE` | 413 | Upload a smaller file (10 MB at most). |

### Telegram and cabinet state

| Code | HTTP | What to do |
|---|---|---|
| `PLATFORM_REJECTED` | 400 | Telegram refused the change; `error` carries its reason. With a low bid you also get `param: "cpm"`, `min_cpm` and `currency`. |
| `BUDGET_UNCHANGED` | 400 | Telegram accepted the top-up but the campaign's budget didn't move. Check the cabinet balance (`GET /v1/account/info`). |
| `INSUFFICIENT_AD_BALANCE` | 400 | You asked to withdraw more than the campaign has. Withdraw less, or use `withdraw_all`. |
| `CABINET_AUTH_EXPIRED` | 409 | The cabinet's Telegram session expired. The owner reconnects it in the panel; then retry. |
| `CABINET_LOCKED` | 409 | The cabinet is under automatic management; manual changes are blocked. |

### Limits and retries

| Code | HTTP | What to do |
|---|---|---|
| `RATE_LIMITED` | 429 | Wait `Retry-After` seconds. See [Rate limits](https://adsly.pro/docs/api/rate-limits.md). |
| `QUEUE_FULL` | 429 | The cabinet already has 5 operations queued. Wait for a task to finish, then retry (same `Idempotency-Key` is fine). |
| `IDEMPOTENCY_KEY_REQUIRED` | 400 | Add an `Idempotency-Key` header. |
| `IDEMPOTENCY_KEY_INVALID` | 400 | Use 8–255 characters; a UUID is ideal. |
| `IDEMPOTENCY_KEY_REUSED` | 422 | That key was used for a different request — new operation, new key. |
| `IDEMPOTENCY_IN_PROGRESS` | 409 | The first request with this key is still running. Retry in a few seconds. |
| `IDEMPOTENCY_UNAVAILABLE` | 503 | Nothing was done. Retry with the same key. |
| `INGEST_DISABLED` | 403 | Turn on **Receive postbacks** for the key ([Conversions](https://adsly.pro/docs/api/conversions.md)). |
| `INTERNAL_ERROR` | 500 | Our side. Check the state with a GET before retrying a write; contact [@adsly_pro](https://t.me/adsly_pro) with the `request_id` if it persists. |

## Retrying safely

- **4xx** — don't retry unchanged; fix the request. (A 4xx never consumes your `Idempotency-Key`, so you can retry the fixed request with the same key.)
- **429 / 503** — retry after `Retry-After`.
- **5xx after a write** — the change may or may not have reached Telegram. Retrying with the **same** `Idempotency-Key` returns the same 5xx (by design — it prevents a double action). `GET` the campaign to see what happened, then decide; if you retry, use a new key.
- **Network timeout on a write** — retry with the **same** `Idempotency-Key`. If the first attempt went through you get its result; if it didn't, the operation runs now.

---
Page: https://adsly.pro/docs/api/errors/ · Updated: 2026-10-08
