Documentation sections

Admin API: spend

Four Admin API methods for spend: the state by day, settings, receiving a daily snapshot of an ad account and downloading the extension.

These methods power the Settings → Spend («Настройки → Расходы») tab and the spend extension. You can also use them to send the spend of an ad account to the tracker from your own integration. Authorization is described on the Admin API: overview and authorization page, and the response and error format on the Request, response and error format page.

Access and license

Methodspend:writefull
GET /api/v1/spendyesyes
POST /api/v1/spend/snapshotsyesyes
PUT /api/v1/spend/settingsnoyes
GET /api/v1/spend/extensionnoyes

A spend:write token is created in the panel: Settings → Spend, the Connect profile («Подключить профиль») block, the Create key («Создать ключ») button. Such a key is valid for 90 days. A full token is created on the API tab — see Access types.

All four methods work only on a paid license. On a trial license they respond with code 403:

json
{"code": "spend_paid_required", "message": "Расширение для расходов доступно после оплаты лицензии."}

The message means “the spend extension is available after the license is paid for”. When the license is inactive, the response is 402, see Expired license.

Methods

Get the settings and the state of days

http
GET /api/v1/spend

Returns the spend settings and the state of the last 60 days for which snapshots arrived.

Token scope: spend:write or full. There are no parameters and no body.

Response — code 200:

FieldTypeDescription
settings.ad_keystringThe click field that carries the ad ID. Until the settings are saved — sub_id_4
settings.timezonestringThe value saved back when the time zone was a setting; without it — UTC. It is not used in the calculation: each account is counted in its own time zone. Extension versions below 1.1.0 check the account's time zone against it
jobsarrayDays with snapshots, from newest to oldest. If there were no snapshots — []
jobs[].daystring, YYYY-MM-DDSpend date. For each account, it is the day in that account's time zone
jobs[].pendingbooleantrue — the snapshot is accepted and waits to be distributed across campaigns, false — the spend is counted in the reports
jobs[].errorstringError text of the last distribution. An empty string if there is no error. The tracker repeats the distribution on its own
jobs[].campaignsnumberHow many campaigns received spend for the day
jobs[].unmatched_adsnumberHow many ads are not matched: there are no clicks with their ID for the day
jobs[].unmatched_spendnumberSpend of these ads in USD
jobs[].updated_atstring, RFC 3339 dateTime of the last change

The same data is shown in the table on the Spend tab — see Days table.

Example response:

json
{
  "settings": {"ad_key": "sub_id_4", "timezone": "Europe/Warsaw"},
  "jobs": [
    {
      "day": "2026-10-03",
      "pending": false,
      "error": "",
      "campaigns": 4,
      "unmatched_ads": 1,
      "unmatched_spend": 3.2,
      "updated_at": "2026-10-04T06:15:22.104512Z"
    }
  ]
}

Save the spend settings

http
PUT /api/v1/spend/settings

Sets the click field with the ad ID. In the panel, this is the Ad ID field («Поле с ID объявления») list. The time zone is not configured: each snapshot passes it.

Token scope: full.

FieldTypeRequiredDescription
ad_keystringyesOne of the values sub_id_1 … sub_id_30
timezonestringnoAn optional field from earlier versions: the value is saved and returned in settings.timezone, but it is not used in the calculation. If passed, it must be a time zone in IANA format; the value Local is not accepted. Without the field, the saved value does not change

Response — code 200 and the saved values:

json
{"ad_key": "sub_id_4", "timezone": "UTC"}
Warning.

The field can be changed until the tracker has accepted a single snapshot. After the first snapshot it is locked, and the method responds 409. Check the value before the first spend upload.

Errors:

CodecodemessageWhen
422validationВыберите sub_id_1…30 с ID объявления (choose the sub_id_1…30 with the ad ID)The body could not be parsed or ad_key is outside the list
422validationУкажите IANA timezone рекламного кабинета (specify the IANA timezone of the ad account)timezone is passed, but it is unknown or equal to Local
409spend_historyПосле первого импорта поле с ID объявления фиксировано, чтобы не пересчитать историю другим способом (after the first import, the ad ID field is locked so that the history is not recalculated in a different way)The tracker already has at least one snapshot

Send a daily spend snapshot

http
POST /api/v1/spend/snapshots

Accepts the full spend of one ad account for one day: a list of ads and the amount for each of them.

Token scope: spend:write or full. The body is one JSON object up to 2 MiB in size. Fields that are not in the table cause a 422 error.

FieldTypeRequiredDescription
account_idstringyesAd account ID: digits only, from 1 to 32 characters
daystring, YYYY-MM-DDyesSpend date in the timezone time zone. Today or one of the 30 previous days in that time zone
currencystringyesAccount currency: three Latin letters, for example PLN. Case does not matter
timezonestringyesTime zone of the ad account in IANA format, for example America/Los_Angeles. Each account has its own: the spend of a day is distributed across the clicks that arrived on that day in that time zone. The value Local is not accepted
fetched_atstring, RFC 3339 dateyesWhen the data was received from the ad account. No older than 24 hours and no more than 5 minutes in the future
rowsarrayyesThe account's ads for the day, up to 10,000 rows. An empty array resets the account's spend for this day to zero. A request without the field is processed as an empty array
rows[].ad_idstringyesAd ID: digits only, from 1 to 32 characters. No repeats within a snapshot
rows[].spendnumberyesAd spend for the day in the currency currency, from 0 to 1,000,000,000

How the tracker processes a snapshot:

  • A snapshot replaces the earlier data of this account for this day rather than adding to it. Send all of the account's ads, not only the ones that changed.
  • Of two snapshots of the same account for the same day, the one with the later fetched_at is kept. A snapshot with an earlier time is not applied.
  • The amount is converted to USD at the rate for the spend date. The rate is fixed for the account and day with the first snapshot — see Rate for extension spend. USD does not need a rate.
  • An ad's spend is split between campaigns by the clicks with its ID in the settings.ad_key field — see How spend gets into reports.

Response — code 202: the snapshot is accepted, and the distribution across campaigns runs in the background. Check the result in jobs of the GET /api/v1/spend method.

FieldTypeDescription
acceptedbooleanAlways true
changedbooleantrue — the snapshot is saved, and the day is queued for distribution. false — the tracker already has a snapshot with the same or a later fetched_at, the data did not change
rowsnumberHow many rows the request had

Example request:

bash
curl -X POST https://panel.example.com/api/v1/spend/snapshots \
  -H "Api-Key: <token>" \
  -H "Content-Type: application/json" \
  -d '{
    "account_id": "1234567890123456",
    "day": "2026-10-03",
    "currency": "PLN",
    "timezone": "Europe/Warsaw",
    "fetched_at": "2026-10-04T06:15:00Z",
    "rows": [
      {"ad_id": "120210000000000001", "spend": 182.4},
      {"ad_id": "120210000000000002", "spend": 57.15}
    ]
  }'

Example response:

json
{"accepted": true, "changed": true, "rows": 2}

Errors:

CodecodemessageWhen
422validationvarious, see the list belowAn error in the body or in the field values
422currency_rateНет курса USD на дату расхода; добавьте курс и повторите (there is no USD rate for the spend date; add a rate and repeat)There is no rate for currency on the day date — see If there is no rate
422snapshot_limitЛимит дня: 100 аккаунтов, 100000 объявлений и допустимая сумма USD; ad_id должен принадлежать одному аккаунту (daily limit: 100 accounts, 100000 ads and an allowed USD amount; an ad_id must belong to one account)More than 100 accounts or 100,000 ads for the day, the day's total in USD is greater than 1,000,000,000, or this ad_id has already come from another account for the day
409currency_mismatchВалюта сохранённого снимка отличается (the currency of the saved snapshot is different)The account has already been uploaded for this day in a different currency
409snapshot_conflictСнимки с одинаковым временем содержат разные данные; выполните новый сбор (snapshots with the same time contain different data; collect again)fetched_at matches the saved one, but the rows are different. Send a snapshot with a new time
429rate_limitedслишком много запросов, попробуйте позже (too many requests, try again later)More than 120 requests per minute from one IP — see Rate limits
Messages with the validation code
  • Некорректный снимок расходов (до 2 МиБ) (invalid spend snapshot, up to 2 MiB) — the body is not JSON, is larger than 2 MiB, has an unknown field or a value of the wrong type.
  • Ожидается один JSON снимок (a single JSON snapshot is expected) — there is more data in the body after the object.
  • Некорректный аккаунт, валюта или размер снимка (до 10000 объявлений) (invalid account, currency or snapshot size, up to 10000 ads) — an error in account_id or currency, or more than 10,000 rows.
  • Некорректная timezone (invalid timezone) — timezone is empty, unknown or Local.
  • Дата должна быть в пределах последних 31 дней (the date must be within the last 31 days) — day is in a different format, in the future or older than 30 days.
  • Обновите снимок расхода: время получения устарело или находится в будущем (refresh the spend snapshot: the receipt time is out of date or in the future) — fetched_at is not set or is outside the allowed window.
  • Некорректный расход или повтор ID объявления (invalid spend or repeated ad ID) — an error in ad_id, a repeated ad_id, a negative or too large spend.
  • Суммарный расход слишком велик (the total spend is too large) — the sum of the snapshot rows in the currency currency is greater than 1,000,000,000.
  • Недопустимый курс или сумма USD (unacceptable rate or USD amount) — the snapshot amount after conversion to USD is greater than 1,000,000,000.

Repeating the same snapshot with the same fetched_at is safe: the tracker responds 202 with "changed": false.

Download the extension

http
GET /api/v1/spend/extension

Returns the spend extension archive built for the panel domain, name and logo of this installation. It is the same file that the button on the Spend tab downloads — see Facebook spend extension.

Token scope: full. There are no parameters and no body.

Response — code 200, type application/zip, file name micator-spend.zip.

Example request:

bash
curl https://panel.example.com/api/v1/spend/extension \
  -H "Api-Key: <token>" \
  -o micator-spend.zip

Errors:

CodecodemessageWhen
503extension_configПроверьте домен панели и логотип в конфигурации установки (check the panel domain and logo in the installation configuration)The archive was not built — see The archive doesn't download

Uploading from your own integration

  1. Save the settings with the PUT /api/v1/spend/settings method or on the Settings → Spend tab.
  2. Send one POST /api/v1/spend/snapshots request for each “account — day” pair.
  3. Request GET /api/v1/spend and wait until the day you need has "pending": false with an empty error.
  4. If unmatched_ads is not zero, check that the link in the ad passes the ad ID in the settings.ad_key field — see Source tokens and link parameters.

To distribute the spend across clicks that arrived after the upload, send the snapshot of that day again with a new fetched_at.

Updated Need help? ↗