Public HTTP API
The Adset.pro public HTTP API gives external systems programmatic access to the data and entities of your account: BI tools and dashboards, ETL scripts, and automation that creates campaigns, affiliate networks, offers and flows.
Base URL: https://adset.pro. Swagger UI: https://adset.pro/api/docs (OpenAPI 3.0; JSON spec — https://adset.pro/api/docs/swagger.json).
The public API consists of the same endpoints the web cabinet uses: there is no separate /api/public/* layer. Request and response fields match what the UI shows, and data visibility is the same as in the cabinet. The articles in this section list the required and key fields; full schemas are in Swagger.
Articles in this section
| Group | Scopes | Article |
|---|---|---|
| Statistics reports, CSV, field catalogs | api:stats, api:stats:export, api:stats:meta |
Statistics: reports and export |
| Filter, grouping and metric keys | — | Statistics: field reference |
| Campaigns | api:campaigns, api:campaigns:write |
Campaigns |
| Affiliate networks (CPA) | api:cpa, api:cpa:write |
Affiliate networks (CPA) |
| CPA templates | api:cpa |
CPA templates |
| Offers | api:offers, api:offers:write |
Offers |
| Flows | api:flows, api:flows:write |
Flows |
| Domains | api:domains |
Domains |
Quick start
- In the cabinet open User settings → the "MCP keys" tab (
https://adset.pro/user-settings), click "Create API key" and choose the Personal Access Token type. Copy the token right away — it is shown only once. - Send the token with every request in the
Authorization: Bearer pat_…header. - Check access with a catalog request:
curl 'https://adset.pro/api/stats/meta/metrics' \
-H 'Authorization: Bearer pat_XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
- Entity lists are paginated on the server:
GET /api/campaigns?page=1&pageSize=100. - To create or edit entities, add write scopes to the key — a new PAT is read-only by default.
Getting a token
Personal Access Token (PAT)
The primary option for scripts and server-side integrations. The token prefix is pat_, the length is about 64 characters.
A key is created in the UI (see "Quick start") or with a request from the cabinet — it requires the browser session JWT, not another PAT:
POST /api/mcp/keys
Authorization: Bearer <cabinet session JWT>
Content-Type: application/json
{
"type": "pat",
"name": "BI ETL job",
"scopes": ["api:stats", "api:stats:meta", "api:campaigns"],
"expiresInDays": 365
}
The response returns the token field once — store it.
| Parameter | Rule |
|---|---|
type |
pat — for the HTTP API. The mcp value issues a key for /mcp, which does not work on /api/* |
name |
1–100 characters |
scopes |
a list from the "Scopes" table. Unknown values are dropped; without the parameter the key gets read scopes only |
expiresInDays |
1–3650; without the parameter the key never expires |
Key management (from the cabinet; a user sees only their own keys):
| Action | Endpoint |
|---|---|
| List your keys | GET /api/mcp/keys |
| Create a key | POST /api/mcp/keys |
| Rotate — the old key is revoked, a new one is issued with the same name and scopes | POST /api/mcp/keys/{keyId}/rotate |
| Change the scope set | PATCH /api/mcp/keys/{keyId}/scopes with body { "scopes": [...] } |
| Revoke a key | DELETE /api/mcp/keys/{keyId} |
All of these actions are also available in the UI on the "MCP keys" tab.
pat_is accepted only on/api/*paths. It is rejected on/mcp— that endpoint needs an MCP key (mcp_) or an OAuth token, see MCP Service Adset.
OAuth 2.0 (for applications)
OAuth tokens (oat_…, Authorization Code + PKCE) are also accepted on /api/* with the same scopes. This flow exists primarily to connect MCP clients (ChatGPT, Claude and compatible tools) and is described in MCP Service Adset. Discovery document: GET /.well-known/oauth-authorization-server. For scripts and server-side integrations use a PAT.
Scopes
A scope is the token's own permission to call a group of endpoints. Effective access = token scopes ∩ the permissions of the token owner's role.
| Scope | What it allows | In the PAT default |
|---|---|---|
api:stats |
POST /api/stats/query — statistics reports |
yes |
api:stats:export |
POST /api/stats/export/csv — CSV export |
yes |
api:stats:meta |
GET /api/stats/meta/* — catalogs of metrics, groupings, filters |
yes |
api:campaigns |
read campaigns | yes |
api:campaigns:write |
create and edit campaigns | no |
api:cpa |
read CPA networks and CPA templates | yes |
api:cpa:write |
create and edit CPA networks | no |
api:offers |
read offers | yes |
api:offers:write |
create and edit offers | no |
api:flows |
read flows | yes |
api:flows:write |
create and edit flows | no |
api:domains |
read domains | yes |
- A new PAT without an explicit
scopeslist gets all read scopes. Write scopes are enabled when the key is created or later — via the UI orPATCH /api/mcp/keys/{keyId}/scopes. - Previously issued keys do not receive new scopes automatically: add them the same way.
- No scope grants deletion — entities cannot be deleted through the API.
Permissions of the token owner's role
A token acts on behalf of the user who created it and inherits their role and data visibility:
| Role | What it sees and changes through the API |
|---|---|
| ADMIN | all platform data |
| TEAM_OWNER, TEAM_LEAD, TECH | the data of their team (TEAM_LEAD — subject to resource access settings) |
| BUYER | only their own entities and statistics, subject to access granted by the team lead |
All roles can read and create/edit campaigns, offers and flows, create CPA networks, and read domains, CPA templates and statistics. The single exception: BUYER cannot edit CPA networks — PATCH /api/cpa/{id} returns 403. An entity of another team or user does not exist for the token: the response is 404, not 403.
Common conventions
Request and response format
- JSON, UTF-8,
Content-Type: application/json. Dates are ISO 8601 in UTC.{id}identifiers are 24-character hex ObjectIds. - Single object:
{ "data": { … }, "traceId": "…" }. - List:
{ "data": [ … ], "meta": { "page", "pageSize", "total", "sort", "filters" }, "links": { "self", "next"?, "prev"? }, "traceId": "…" }. - Creation —
201 Createdwith aLocation: /<resource>/{id}header; editing —200 OKwith the full object. - Every response contains
traceIdand theX-Trace-Idheader — quote it when contacting support.
List parameters (GET …)
A single contract for all entity lists. The allowed filter and sort fields differ per entity — they are listed in each group's article.
| Parameter | Format | Note |
|---|---|---|
page |
integer ≥ 1 | default 1 |
pageSize |
1–1000 | default 10 |
sort |
field:asc / field:desc; several — comma-separated or by repeating the parameter; -field = field:desc |
unknown fields are ignored |
filter[field]=v |
equality; a string prefixed with @ — substring search |
unknown fields are ignored |
filter[field][op]=v |
eq, ne, gt, gte, lt, lte, in, nin, contains, startsWith, endsWith |
in/nin — CSV or a repeated parameter |
populate |
populate=user,team or populate[user]=name,email; an empty populate= disables reference expansion |
without the parameter the default set applies (listed in the group's article) |
select |
select=name,isActive — return only these fields |
curl -G 'https://adset.pro/api/offers' \
-H 'Authorization: Bearer pat_…' \
--data-urlencode 'page=1' \
--data-urlencode 'pageSize=100' \
--data-urlencode 'sort=updated:desc' \
--data-urlencode 'filter[isActive]=true' \
--data-urlencode 'filter[country][in]=DE,AT'
meta.total is the total number of records; the last page has no next in links. If you need a full catalog, request it page by page or pass pageSize up to 1000.
Errors
The error body is uniform: { "error": { "code": "…", "message": "…", "details": [ … ] }, "traceId": "…" } (details lists per-field violations and is not always present).
| HTTP | error.code |
When |
|---|---|---|
400 |
validationError |
a request rule is violated: campaign alias already taken, the token owner has no team, no time in a report |
401 |
unauthorized |
no Authorization header; the token is expired, revoked or of the wrong type (e.g. mcp_ on /api/*) |
403 |
forbidden, message starts with Insufficient OAuth scope. Required: … |
the token lacks the required scope |
403 |
forbidden |
the token owner's role lacks the permission (e.g. a BUYER editing a CPA network); tell it apart from the previous row by message |
404 |
notFound |
the entity does not exist or belongs to another team/user |
422 |
validationError |
the body failed schema validation: missing required field, wrong enum or format; fields are listed in details[] |
429 |
— | the request rate limit is exceeded; returned by the gateway, without traceId |
On /mcp, authorization errors use the OAuth format ({ "error": "invalid_token", … }); on /api/* the format is always as in the table.
Limits
| Parameter | Value |
|---|---|
| Request rate (per IP) | /api/stats/** — 3 requests/s (burst 10); other /api/** — 20 requests/s (burst 40). Above the limit — 429 |
List pageSize |
≤ 1000 |
pagination.limit in /api/stats/query |
≤ 100,000; ≤ 10,000 recommended |
| CSV export | up to 100,000 rows |
| PAT name / lifetime | ≤ 100 characters / expiresInDays 1–3650 or unlimited |
Recommendations: cache catalogs (/api/stats/meta/*, CPA templates), request only the fields you need (select), and retry with exponential backoff on 429.
What is not part of the public API
Deleting entities, copying (/copy, /clone), bulk operations (/reassign-owner, /replace-domain), server-side tables (/table), /free-list, a campaign's domain list, the domain registration wizard and domain purchase, Cloudflare operations, creating and editing CPA templates and domains. These endpoints have no scope, are not published in /api/docs, and their contract is not guaranteed and may change without notice. Do not use them from integrations — PAT/OAuth access to them will be closed.
Useful links
- Swagger UI:
https://adset.pro/api/docs - MCP Service Adset — LLM client access to data via the Model Context Protocol and OAuth 2.0
- Report Builder — the same metrics and groupings in the cabinet UI
