> 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

# Keys and access

How API keys work — read-only and campaign-managing keys, which cabinets a key reaches, how agency owners and team members use the API, and how to keep keys safe.

## Send the key

Every request carries the key in a header:

```
X-API-Key: adsly_0f3c…   (54 characters, starts with adsly_)
```

There is no OAuth flow and no token exchange — the key is the credential. Keep it on your server; never ship it to a browser or a mobile app.

## Get a key

In the panel: **API & Webhooks** → **+ New key**. Keys are part of the **Pro** and **Agency** plans; each person can hold up to 5 active keys. A key is shown **once**, right after you create it — we store only its SHA-256 hash and cannot show it again. Lost it? Revoke it and create a new one.

## What a key can do

| Permission | How you get it | What it allows |
|---|---|---|
| **Read** | every key | campaigns, stats, conversions, tasks, targeting codes, webhooks, sending conversions to us |
| **Manage campaigns** | tick **Allow managing campaigns** when you create the key, or switch it on later on the key's card | everything in Read, plus create, edit, pause/resume, budget, copy, bulk actions, delete, media upload |

A read-only key that calls a write endpoint gets `403 READ_ONLY_KEY`. Give dashboards and reporting tools a read-only key; give a manage key only to code you trust to change campaigns. No key — read or manage — can take money out of a cabinet: budget moves only between the cabinet balance and its campaigns.

Writes also need an active Pro or Agency plan at the moment of the call (`403 FEATURE_NOT_AVAILABLE` otherwise) and the same per-feature plan rights the panel checks.

## Which cabinets a key reaches

When you create a key you choose its scope:

| Scope | The key reaches |
|---|---|
| All my cabinets (default) | every cabinet you can open in the panel, including ones added later |
| Several | the cabinets you ticked |
| One cabinet | that cabinet only |

The scope only ever **narrows** what you can open in the panel — it never widens it. It is re-checked on every request: when you lose access to a cabinet, your keys lose it in the same moment. `GET /v1/account/info` always lists exactly what the key reaches right now.

If a key reaches several cabinets, pass `account_id` on calls that act on one of them (`400 ACCOUNT_ID_REQUIRED` tells you when it's missing).

## Agencies and team members

API access follows the access you have in the panel, cabinet by cabinet:

| Who you are | Cabinets your key reaches | Can manage campaigns in |
|---|---|---|
| Account owner (regular user) | your own cabinets | all of them |
| Agency owner | your personal and agency cabinets | all of them |
| Agency team member | the cabinets the agency shared with you | cabinets shared with **Manager** access; **Viewer** cabinets stay read-only |

- Team members create their own keys on their own **API & Webhooks** page. The agency's plan covers them.
- The agency owner sees every key the team created under **API & Webhooks → Team keys** — whose it is, whether it can manage campaigns, how many cabinets it reaches, when it was last used — and can revoke any of them.
- `GET /v1/account/info` returns `access_level` for each cabinet: `owner`, `manager` or `viewer`. A write to a `viewer` cabinet returns `403 VIEW_ONLY_ACCESS`.
- If the owner removes a member, lowers them to Viewer, or the agency plan ends, the member's keys follow immediately — nothing to revoke by hand.

What the roles mean in the panel: **Manager** — full campaign management in that cabinet; **Viewer** — campaigns and stats only. The owner can also let a member add cabinets, invite teammates or share their own cabinets (never above their own level).

## Revoke and rotate

- **Revoke** a key on its card in the panel. It stops working immediately.
- **Rotate** = create a new key, deploy it, then revoke the old one. Two keys can be active at once, so there is no downtime.
- The **webhook secret** (for verifying [webhooks](https://adsly.pro/docs/api/webhooks.md)) is separate from the key and can be rotated on its own.

## Keep keys safe

- One key per integration, so you can revoke one without breaking the others.
- Store keys in environment variables or a secret manager. Never commit them, never paste them into chats or tickets.
- Prefer read-only keys; add **Manage campaigns** only where the code changes campaigns.
- Narrow the scope to the cabinets an integration needs.
- If a key may have leaked, revoke it first and investigate second. Every change made through the API appears in the campaign's history in the panel marked **🔌 API**.

## Errors you can get here

| HTTP | `code` | Meaning |
|---|---|---|
| 401 | `API_KEY_MISSING` | no `X-API-Key` header |
| 401 | `API_KEY_INVALID` | wrong, revoked or expired key |
| 401 | `NO_ACCOUNTS` | the key reaches no active cabinet right now |
| 403 | `READ_ONLY_KEY` | a write with a key that doesn't have Manage campaigns |
| 403 | `VIEW_ONLY_ACCESS` | a write to a cabinet shared with you as Viewer |
| 403 | `FEATURE_NOT_AVAILABLE` | the plan doesn't include this action |
| 403 | `WRITE_NOT_ALLOWED` | this kind of key (issued by Adsly for partners) can't write |

Full list: [Errors](https://adsly.pro/docs/api/errors.md).

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