API v3

Вопросы по API

То, что разработчики спрашивают до и во время подключения: ключи, ссылки, как решение попадает на ваш сайт, вебхуки, журнал, лимиты и ошибки. Все методы и цифры здесь те, с которыми API работает сейчас.

Адрес
https://api.consent.link/v3
Ключ
Authorization: Bearer clk_live_…
Формат
JSON, UTF-8, ответы на английском

Начало работы

Как получить ключ API?

Зарегистрируйтесь и подтвердите почту. Первая страница после входа, «Подключение по API», создаёт ваш ключ clk_live_….

Ключ показывается один раз, сразу после создания, поэтому скопируйте его сразу: мы храним только его хэш. У аккаунта может быть до 10 действующих ключей. Ненужный ключ отзывается на той же странице и сразу перестаёт работать.

Где находится API и как передать ключ?

API находится по адресу https://api.consent.link/v3 и работает с JSON. Передавайте ключ в каждом запросе в заголовке Authorization: Bearer clk_live_… (заголовок X-AUTH-TOKEN из старого API v2 тоже принимается). Запрос без действующего ключа получает 401 unauthenticated.

Вызывайте API только со своего сервера. Тот, у кого ключ, может создавать ссылки и читать ваш журнал с полными данными посетителей.

Запрос
curl https://api.consent.link/v3/usage \
  -H "Authorization: Bearer clk_live_…"
Ответ
{
  "consents": 412,
  "limit": 1000,
  "remaining": 588,
  "period_start": "2026-11-01T00:00:00.000Z",
  "period_end": "2026-12-01T00:00:00.000Z"
}

Какие есть методы?

Все сразу. Каждый путь идёт после https://api.consent.link; открытые ключи для проверки токенов решения лежат на https://app.consent.link/.well-known/jwks.json.

МетодЧто делает
POST/v3/linksСоздать ссылку
POST/v3/links/bulkСоздать до 500 ссылок
GET/v3/linksСписок ссылок с фильтрами
GET/v3/links/{id}Одна ссылка и её цифры
PATCH/v3/links/{id}Изменить ссылку
DELETE/v3/links/{id}Отключить ссылку
GET/v3/profilesСписок конфигураций
POST/v3/profilesСоздать конфигурацию
GET/v3/profiles/{id}Одна конфигурация
PATCH/v3/profiles/{id}Изменить или опубликовать конфигурацию
DELETE/v3/profiles/{id}Удалить конфигурацию
POST/v3/consents/verifyПроверить токен решения, один раз
GET/v3/webhooksСписок вебхуков
POST/v3/webhooksДобавить вебхук
GET/v3/webhooks/{id}Один вебхук
PATCH/v3/webhooks/{id}Изменить адрес, события или включить и отключить
DELETE/v3/webhooks/{id}Удалить вебхук
GET/v3/consentsЖурнал с фильтрами
GET/v3/consents/{id}Одна запись с доказательствами
POST/v3/consents/{id}/withdrawОтозвать согласие от имени посетителя
GET/v3/consents/{id}/proofPDF-доказательство записиPro и Business
GET/v3/consents/{id}/snapshotСтраница, которую видел посетитель, в HTML
GET/v3/consents/{id}/snapshot.pngСтраница, которую видел посетитель, скриншотом
POST/v3/exportsЗапустить выгрузку CSVPro и Business
GET/v3/exports/{id}Выгрузка и её состояниеPro и Business
GET/v3/exports/{id}/fileСкачать CSVPro и Business
GET/v3/stats/summaryИтоги за период
GET/v3/stats/dailyЦифры по дням (и странам)
GET/v3/usageСогласия за период и лимит

Страница согласия

Что увидят посетители и на каком языке?

Страницу, которую вы настроили в «Оформление» в кабинете: шаблон текста из нашей библиотеки, получатели данных, подпись, ссылка на вашу политику конфиденциальности, а на Business ваши логотип и цвет. Собственные type и template ссылки важнее оформления. Когда вы публикуете новую версию, страницы ваших ссылок меняются в течение минуты.

Язык выбирается по браузеру посетителя: английский, испанский, немецкий, французский, итальянский, португальский или русский. Вы выбираете шаблон, а не слова: тексты берутся из нашей библиотеки, свой написать нельзя.

Пока в «Оформление» ничего не опубликовано, страница показывается без ссылки на вашу политику конфиденциальности и без получателей данных. Ссылки при этом создаются, а ответы POST /v3/links, POST /v3/links/bulk и PATCH /v3/links/{id} несут заголовок Consent-Link-Warning: design_unpublished, пока у конфигурации ссылки нет опубликованной версии.

Как сделать разным ссылкам разное оформление?

Сохраните несколько конфигураций страницы в «Оформление» или через API, у каждой свой ID, например black-friday, и укажите нужную при создании ссылки: "profile": "black-friday" в POST /v3/links или в элементе массового создания. Без profile ссылка получает основную конфигурацию.

Ссылка запоминает свою конфигурацию: если потом сделать основной другую, старые ссылки не меняются. PATCH /v3/links/{id} с profile переводит одну ссылку, а "profile": null переводит её на основную конфигурацию этого момента. Неизвестный ID даёт 422 по полю profile. В объекте ссылки видно её поле profile, а GET /v3/links?profile=black-friday выдаёт ссылки одной конфигурации. Сколько конфигураций можно держать, зависит от тарифа: 1 на Free, 5 на Pro, 50 на Business, включая основную.

Как управлять конфигурациями через API?

GET /v3/profiles выдаёт список, основная первой. POST /v3/profiles создаёт конфигурацию с id и policy_url (обязательны) и, по желанию, name, template, vendors, type, remember, brand_name и default. Она публикуется сразу. PATCH /v3/profiles/{id} меняет её: поля страницы сразу публикуют новую версию, а одни name и "default": true ничего не публикуют.

DELETE /v3/profiles/{id} удаляет конфигурацию, если она не основная (409 profile_is_default) и на неё не ведёт ни одна действующая ссылка (409 profile_in_use). Создание сверх лимита тарифа или использование конфигурации, оказавшейся сверх лимита после понижения тарифа, даёт 402 profiles_limit_reached. Изменения требуют боевого ключа.

Что происходит с параметрами в моём адресе, например utm или gclid?

С согласием посетитель попадает на ваш адрес ровно в том виде, в каком вы его дали. Без согласия utm_* и остальные ваши параметры тоже остаются, убираются только ID рекламных кликов: gclid, gbraid, wbraid, fbclid, msclkid, ttclid, twclid, li_fat_id. В обоих случаях мы добавляем один параметр, cl_ct, это токен решения.

Учитываются только параметры самого адреса назначения: то, что дописано к короткой ссылке (https://consent.link/nk7Qa?utm_source=…), дальше не передаётся. Кладите всё, что нужно сайту, в destination или делайте ссылку на каждую кампанию.

Куда уходит посетитель: с согласием, затем без
https://shop.example/sale?utm_source=insta&gclid=Cj0K…&cl_ct=eyJhbGciOiJFUzI1NiIs…
https://shop.example/sale?utm_source=insta&cl_ct=eyJhbGciOiJFUzI1NiIs…

Решения и вебхуки

Как мой сайт узнаёт, что решил посетитель?

Каждый переход со страницы согласия несёт cl_ct, подписанный токен (JWT, ES256), который живёт 10 минут. Проверьте его со своего сервера через POST /v3/consents/verify: в ответе решение, а каждый токен проверяется один раз, поэтому скопированный адрес ничего не даёт. Прочитайте токен и уберите его из адреса.

Что в нём: decision (granted или denied), purposes (что посетитель разрешил), cid (запись в журнале), sid (псевдоним посетителя в вашем аккаунте, одинаковый на всех ваших ссылках), cexp (до какого времени действует согласие, Unix-время), link, mode, iat и exp. Ни IP, ни браузера, ни других персональных данных. Посетитель, который уже соглашался и оставил «Не спрашивать снова», проходит сразу, с granted.

Подпись можно проверить и самому ключами с https://app.consent.link/.well-known/jwks.json и любой библиотекой JWT: проверьте exp и что link ваша. Собственная проверка не узнает, использовался ли токен раньше, метод API узнает. Ошибки: 422 token_invalid, 422 token_expired, 409 token_used.

Запрос
curl -X POST https://api.consent.link/v3/consents/verify \
  -H "Authorization: Bearer clk_live_…" \
  -H "Content-Type: application/json" \
  -d '{"token": "eyJhbGciOiJFUzI1NiIs…"}'
Ответ
{
  "decision": "granted",
  "purposes": ["stats", "ads"],
  "cid": "01jbz8m3k4x9w2r7d5t6q8v1yh",
  "sid": "psd_Qm9xV3c…",
  "cexp": 1809345604,
  "link": "nk7Qa",
  "mode": "live",
  "iat": 1793712004,
  "exp": 1793712604
}

Как получать решения на свой сервер сразу?

Создайте вебхук: POST /v3/webhooks с url и нужными events (таблица ниже). Адрес должен быть https с публичным именем хоста. В ответе secret (whsec_…) для проверки подписи: он показывается один раз, сохраните его. У аккаунта может быть до 10 действующих вебхуков.

Журнал доставок, кнопка «Повторить» и включение и отключение вебхука есть в кабинете в разделе «Аккаунт» → «Вебхуки».

Запрос
curl -X POST https://api.consent.link/v3/webhooks \
  -H "Authorization: Bearer clk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://shop.example/hooks/consent",
    "events": ["consent.recorded", "consent.withdrawn"]
  }'
Ответ
201 Created
{
  "id": "wh_01jbz9a7c2m5n8p3q6r9s2t5v8",
  "url": "https://shop.example/hooks/consent",
  "events": ["consent.recorded", "consent.withdrawn"],
  "mode": "live",
  "status": "active",
  "secret": "whsec_…",
  "created_at": "2026-11-03T12:00:00.000Z"
}

Какие есть события и что в них?

Каждое событие это POST с телом в JSON: id (evt_…), type, created_at, mode и data. Запись о согласии в data.consent содержит id, link, decision, purposes, scope (domain, если посетитель оставил «Не спрашивать снова», иначе link), sid, dest_domain, country, notice_version, created_at и expires_at. Никогда IP, браузер или куку.

СобытиеКогдаdata
consent.recordedНовая запись в журнале: согласие, отказ или посетитель, который уже соглашалсяconsent
consent.withdrawnСогласие отозвано: посетителем на странице «Мои согласия» или вами через APIconsent, withdraws
link.blockedМы заблокировали ссылку, потому что её адрес оказался опаснымlink, destination, reason, message
export.readyВыгрузка CSV готова (или не удалась)id, status, filter, rows, bytes, sha256, file, expires_at
usage.warningИзрасходовано 80 % или 100 % согласий периодаpercent, consents, limit, period_start, period_end
consent.expiredСогласие истекло: оно выдано 6 месяцев назад и с тех пор не отозваноconsent, expired_at
Что получает ваш сервер
POST /hooks/consent
Content-Type: application/json
Consent-Event: consent.recorded
Consent-Delivery: whd_01jbz9d4f7h0k3m6p9r2t5w8y1
Consent-Signature: t=1793712005,v1=5f3a…

{
  "id": "evt_01jbz9d4f6g9j2l5n8q1s4v7x0",
  "type": "consent.recorded",
  "created_at": "2026-11-03T12:00:05.012Z",
  "mode": "live",
  "data": {
    "consent": {
      "id": "01jbz8m3k4x9w2r7d5t6q8v1yh",
      "link": "nk7Qa",
      "decision": "granted",
      "purposes": ["stats", "ads"],
      "scope": "domain",
      "sid": "psd_Qm9xV3c…",
      "dest_domain": "shop.example",
      "country": "DE",
      "notice_version": "statsads-v1",
      "created_at": "2026-11-03T12:00:04.398Z",
      "expires_at": "2027-05-03T12:00:04.398Z"
    }
  }
}

Как проверить, что вебхук пришёл от вас?

В каждом запросе есть заголовки Consent-Event, Consent-Delivery и Consent-Signature: t=1793712000,v1=5f3a…. v1 это HMAC-SHA256 в hex от текста t, точки и сырого тела запроса, с секретом вашего вебхука в качестве ключа.

Считайте подпись от тела ровно в том виде, в каком оно пришло (до разбора JSON), сравнивайте за постоянное время и отклоняйте t, который расходится с вашими часами больше чем на пять минут, чтобы записанный запрос нельзя было повторить.

PHP
$body = file_get_contents('php://input');
parse_str(str_replace(',', '&', $_SERVER['HTTP_CONSENT_SIGNATURE'] ?? ''), $sig);
$expected = hash_hmac('sha256', ($sig['t'] ?? '').'.'.$body, $secret);
if (abs(time() - (int) ($sig['t'] ?? 0)) > 300 || ! hash_equals($expected, $sig['v1'] ?? '')) {
    http_response_code(400);
    exit;
}
Node.js
const crypto = require('node:crypto');
const sig = Object.fromEntries(req.get('Consent-Signature').split(',').map((p) => p.split('=')));
const expected = crypto.createHmac('sha256', secret).update(`${sig.t}.${rawBody}`).digest('hex');
const ok = Math.abs(Date.now() / 1000 - Number(sig.t)) <= 300
  && typeof sig.v1 === 'string' && sig.v1.length === expected.length
  && crypto.timingSafeEqual(Buffer.from(sig.v1), Buffer.from(expected));

Что если мой сервер не работает, когда приходит событие?

Доставка засчитывается, когда ваш сервер отвечает кодом 2xx за 10 секунд; перенаправления не выполняются. Иначе мы повторяем, выжидая между попытками 1 минута, 5 минут, 30 минут, 2 часа, 12 часов, всего 6 попыток. После последней доставка считается неудачной и остаётся в журнале доставок, где кнопка «Повторить» отправляет её снова в течение 3 дней после события.

Поэтому отвечайте быстро, а работу делайте потом. Одно и то же событие может прийти больше одного раза, например после тайм-аута: пропускайте уже обработанные id. События не всегда приходят в том порядке, в каком произошли.

Как отзывается согласие и что происходит потом?

Посетители видят и отзывают свои согласия на странице «Мои согласия». Если посетитель обратился к вам, отзовите согласие за него: POST /v3/consents/{id}/withdraw без тела, с ID его записи granted или reused. Это работает для любого действующего согласия, как бы далеко назад ни показывал журнал ваш тариф. Ответ 201 с новой записью withdrawn, её first_consent_id — отозванное согласие. Запись, которая не является действующим согласием (отказ, уже отозванное или истёкшее), получает 409 consent_not_in_force; запись, которую вы не можете прочитать, получает 404, как у GET /v3/consents/{id}.

Оба способа ведут к одному: запись withdrawn в журнале, consent.withdrawn на ваш вебхук с data.withdraws, ID отозванного согласия, и с этого момента ваши ссылки снова спрашивают этого посетителя. Отзыв закрывает все согласия, которые посетитель дал для этого домена до него, и не расходует лимит.

Перестаньте использовать его данные у себя: сопоставляйте по sid или по ID записи.

Запрос
curl -X POST https://api.consent.link/v3/consents/01jbz8m3k4x9w2r7d5t6q8v1yh/withdraw \
  -H "Authorization: Bearer clk_live_…"
Ответ
201 Created
{
  "id": "01jc4t7v0x3z6b9d2f5h8k1m4p",
  "link": "nk7Qa",
  "decision": "withdrawn",
  "purposes": [],
  "scope": null,
  "sid": "psd_Qm9xV3c…",
  "dest_domain": "shop.example",
  "country": null,
  "notice_version": null,
  "created_at": "2026-12-14T09:30:12.051Z",
  "expires_at": null,
  "first_consent_id": "01jbz8m3k4x9w2r7d5t6q8v1yh",
  "gpc": false,
  "settings_version": null,
  "evidence": null,
  "chain": {…}
}

Сколько действует согласие?

Согласие действует 6 месяцев с момента выдачи: expires_at в записи, cexp в токене решения. Запись reused несёт expires_at того согласия, которое она переиспользует. После этого ваши ссылки снова спрашивают посетителя.

Когда согласие granted истекает, не будучи отозванным, ваш вебхук получает consent.expired с data.consent, самой записью, и data.expired_at. Мы проверяем раз в час, так что событие приходит в течение часа после expires_at, по одному на согласие. У записей reused своего события нет: их покрывает событие согласия, которое они переиспользуют. Событие уходит только на вебхуки, у которых в events есть consent.expired. Об истечении сообщается один раз, даже если тогда его не ждал ни один вебхук: позже оно не повторяется.

Что получает ваш сервер
POST /hooks/consent
Content-Type: application/json
Consent-Event: consent.expired
Consent-Delivery: whd_01jxq3m6p9r2t5w8y1b4d7f0h3
Consent-Signature: t=1809349502,v1=9c1e…

{
  "id": "evt_01jxq3m6p8q1s4v7x0z3b6d9f2",
  "type": "consent.expired",
  "created_at": "2027-05-03T13:05:02.117Z",
  "mode": "live",
  "data": {
    "consent": {
      "id": "01jbz8m3k4x9w2r7d5t6q8v1yh",
      "link": "nk7Qa",
      "decision": "granted",
      "purposes": ["stats", "ads"],
      "scope": "domain",
      "sid": "psd_Qm9xV3c…",
      "dest_domain": "shop.example",
      "country": "DE",
      "notice_version": "statsads-v1",
      "created_at": "2026-11-03T12:00:04.398Z",
      "expires_at": "2027-05-03T12:00:04.398Z"
    },
    "expired_at": "2027-05-03T12:00:04.398Z"
  }
}

Сайт и баннеры

Как сайт сам применяет решение посетителя (Google Consent Mode v2)?

Поставьте наш скрипт в <head> раньше GTM и gtag: https://consent.link/js/consent.js. Он ставит Consent Mode v2 по умолчанию (всё запрещено, кроме functionality_storage и security_storage, с wait_for_update 500 мс), читает cl_ct из адреса, проверяет подпись ключами с https://app.consent.link/.well-known/jwks.json прямо в браузере и обновляет согласие.

Решение запоминается в куке cl_consent на вашем домене: до cexp при согласии и на 180 дней при отказе, так что на следующих страницах баннер не нужен. После проверки cl_ct убирается из адресной строки, остальные параметры остаются. Скрипт ничего нам не отправляет.

Если вы записываете решение у себя, проверяйте токен и на сервере через POST /v3/consents/verify: скрипт не знает, использовался ли токен раньше.

HTML
<script src="https://consent.link/js/consent.js"></script>

Как подключить через Google Tag Manager?

Скачайте шаблон consent-link.tpl, в GTM откройте «Шаблоны» → «Новый» → ⋮ → «Импорт» и сохраните. Создайте тег из шаблона с триггером «Consent Initialization – All Pages» («Инициализация согласия — все страницы»).

Тег ставит значения по умолчанию, применяет решение из куки cl_consent и загружает скрипт, который проверяет свежий cl_ct. Отдельно ставить скрипт в <head> тогда не нужно.

Какие сигналы Consent Mode получает каждая цель?

Цели из purposes токена включают такие сигналы. Всё, что не включено, остаётся запрещённым; при отказе (denied) запрещено всё, кроме двух всегда разрешённых.

ЦельСигналы Consent Mode
stats analytics_storage
ads ad_storage, ad_user_data, ad_personalization
app_install ad_storage, ad_user_data
personalization personalization_storage
Всегда functionality_storage, security_storage

У меня Cookiebot, OneTrust или другой баннер. Что с ним делать?

Не показывайте второй баннер тому, кто уже решил на нашей странице. Скрипт отдаёт решение в window.consentLink.decision (granted, denied или null) и window.consentLink.has('stats'); window.consentLink.ready срабатывает, когда токен из адреса проверен. Ещё есть событие consentlink:update на document и consent_link_update в dataLayer. Ставьте наш скрипт раньше скрипта баннера.

Cookiebot: передайте решение через Cookiebot.submitCustomConsent, и баннер не появится. У OneTrust нет публичной функции, чтобы записать согласие со стороны сайта, поэтому загружайте его скрипт, только когда решения нет. С другими баннерами так же: передайте цели через их API или не загружайте баннер.

Cookiebot
window.addEventListener('CookiebotOnLoad', function () {
  window.consentLink.ready.then(function (cl) {
    if (cl.decision && !Cookiebot.hasResponse) {
      Cookiebot.submitCustomConsent(cl.has('personalization'), cl.has('stats'), cl.has('ads'));
    }
  });
});
OneTrust
window.consentLink.ready.then(function (cl) {
  if (cl.decision) return; // decided on consent.link: no second banner
  var s = document.createElement('script');
  s.src = 'https://cdn.cookielaw.org/scripttemplates/otSDKStub.js';
  s.setAttribute('data-domain-script', 'YOUR-ONETRUST-ID');
  document.head.appendChild(s);
});

Журнал, доказательства и статистика

Как читать журнал?

GET /v3/consents выдаёт записи, сначала новые, с фильтрами decision (granted, denied, reused, withdrawn), link, country (DE), from, to и теми же страницами, что у ссылок. GET /v3/consents/{id} возвращает одну запись с доказательствами (IP-адрес, браузер, язык, хэш текста страницы, когда страница была показана и сколько посетитель думал) и её местом в хэш-цепочке, chain.

Отказ хранит только решение, время, ссылку и страну, поэтому его evidence равно null. API отдаёт данные целиком; кабинет скрывает их часть, пока вы не включите вход с кодом из приложения. Насколько далеко назад видно, зависит от тарифа (таблица в разделе «Тарифы и лимиты»).

Запрос
curl "https://api.consent.link/v3/consents?decision=granted&from=2026-11-01&limit=100" \
  -H "Authorization: Bearer clk_live_…"

Как получить PDF-доказательство согласия?

GET /v3/consents/{id}/proof возвращает запись в PDF: решение, кто, что было показано, хэши и как их проверить. Документ на языке вашего кабинета. Доступно на Pro и Business (на Free 402 plan_required), до 20 в минуту. Если PDF сейчас не получается сделать, ответ 503 unavailable с Retry-After.

Запрос
curl -o proof.pdf https://api.consent.link/v3/consents/01jbz8m3k4x9w2r7d5t6q8v1yh/proof \
  -H "Authorization: Bearer clk_live_…"

Как увидеть и проверить страницу, на которой посетитель дал согласие?

Каждая запись granted несёт evidence.snapshot_hash: SHA-256 страницы согласия в том виде, в каком её увидел посетитель, в HTML. Один снимок служит всем посетителям одной и той же страницы, то есть одной версии оформления и текста, языка и типа ссылки. GET /v3/consents/{id}/snapshot отдаёт этот HTML с хэшем в заголовке X-Snapshot-Hash, а GET /v3/consents/{id}/snapshot.png — его скриншот. Для обоих действуют правила GET /v3/consents/{id}, включая глубину журнала.

Чтобы проверить, посчитайте SHA-256 от HTML ровно в том виде, в каком он пришёл: он равен snapshot_hash, а собственный хэш записи в цепочке покрывает snapshot_hash, так что подменить страницу задним числом нельзя. То, что меняется от показа к показу, в снимке зафиксировано: хост адреса назначения выглядит как example.com, подпись формы пустая, её action — #. Настоящий адрес — в dest_domain и evidence.destination.

У записей reused, отказов и записей, сделанных до появления снимков, snapshot_hash равен null, а их снимок отвечает 404 not_found («This record has no page snapshot.»). Сразу после решения файлы могут ещё записываться: 404 not_found с «The page snapshot is not ready yet.» значит, что стоит повторить чуть позже. HTML появляется за секунды, скриншот немного позже. Страница записи в кабинете и PDF-доказательство тоже показывают скриншот и хэш.

Запрос
curl -o page.html https://api.consent.link/v3/consents/01jbz8m3k4x9w2r7d5t6q8v1yh/snapshot \
  -H "Authorization: Bearer clk_live_…"

sha256sum page.html

Как выгрузить журнал в CSV?

POST /v3/exports с фильтрами GET /v3/consents (decision, link, country, from, to) сразу отвечает 202 с id выгрузки. Файл собирается в фоне: придёт вебхук export.ready, или проверяйте GET /v3/exports/{id}, пока status не станет ready, затем скачайте GET /v3/exports/{id}/file. У выгрузки также есть rows и sha256 файла.

Файлы хранятся 7 дней (потом 410 export_expired). Одновременно может готовиться до 3 выгрузок (429 too_many_exports). Pro и Business.

Запрос
curl -X POST https://api.consent.link/v3/exports \
  -H "Authorization: Bearer clk_live_…" \
  -H "Content-Type: application/json" \
  -d '{
    "decision": "granted",
    "from": "2026-10-01",
    "to": "2026-11-01"
  }'
Ответ
202 Accepted
{
  "id": "exp_01jbz9f2h5k8m1p4r7t0w3y6a9",
  "type": "csv",
  "status": "queued",
  "source": "api",
  "filter": {
    "decision": "granted",
    "from": "2026-10-01T00:00:00.000Z",
    "to": "2026-11-01T00:00:00.000Z"
  },
  "rows": null,
  "bytes": null,
  "sha256": null,
  "created_at": "2026-11-03T12:00:00.000Z",
  "finished_at": null,
  "expires_at": null,
  "file": null
}

Можно получить статистику и расход лимита через API?

GET /v3/stats/summary даёт shown, granted, denied, left, reused и withdrawn за дни по UTC от from до to (2026-10-31, оба включительно; по умолчанию последние 30 дней, не больше 366 дней и не дальше, чем тариф показывает журнал). Добавьте link для одной ссылки. GET /v3/stats/daily даёт те же цифры по дням, а на Pro и Business по странам с by=country. Боты не считаются никогда.

GET /v3/usage показывает согласия за этот период, ваш limit, остаток remaining, начало и конец периода.

Запрос
curl "https://api.consent.link/v3/stats/summary?from=2026-10-01&to=2026-10-31&link=nk7Qa" \
  -H "Authorization: Bearer clk_live_…"
Ответ
{
  "from": "2026-10-01",
  "to": "2026-10-31",
  "link": "nk7Qa",
  "shown": 1840,
  "granted": 1215,
  "denied": 402,
  "left": 198,
  "reused": 25,
  "withdrawn": 3
}

Тарифы и лимиты

Что входит в каждый тариф?

API, вебхуки и страница согласия на семи языках есть на любом тарифе. Тарифы отличаются числом согласий в месяц, глубиной журнала, частотой запросов и дополнительными функциями. Цены в евро без НДС.

ТарифЦена в месяцСогласий в месяцЖурналЗапросов в минутуКонфигурацийЕщё
Free0 €1 000Журнал за 30 дней601—
Pro9 €10 000Журнал за 1 год3005Выгрузка CSV и доказательство в PDF · Статистика по дням и странам
Business99 €250 000Журнал за 3 года1 00050Выгрузка CSV и доказательство в PDF · Статистика по дням и странам · Ваш логотип и цвет · Ссылки на своём домене

Что будет, когда закончатся согласия?

Считаются только новые согласия: отказы, повторные переходы с «Не спрашивать снова», боты не считаются. На 80 % и 100 % лимита приходит письмо и вебхук usage.warning.

Когда лимит исчерпан, новые боевые ссылки отклоняются с 402 limit_reached. Всё остальное работает: старые ссылки по-прежнему спрашивают и записывают, вебхуки и токены приходят как обычно, ничего не скрывается. Создание ссылок открывается в начале следующего периода (на Free 1-го числа, на платных тарифах в день оплаты) или сразу после перехода на тариф выше.

Сколько запросов можно отправлять?

На аккаунт, все ключи вместе: 60 в минуту на Free, 300 на Pro, 1 000 на Business. Сверх этого ответ 429 rate_limited с заголовком Retry-After; заголовки X-RateLimit-Limit и X-RateLimit-Remaining показывают, сколько осталось. У некоторых методов есть и свой лимит: PDF-доказательства 20 в минуту, новые выгрузки 10, скачивание выгрузок 30.

Ошибки и безопасность

Как выглядят ошибки?

Всегда одинаково: HTTP-статус и тело в JSON с постоянным code и сообщением message на английском. Ориентируйтесь на code, текст сообщения может меняться. Неверные поля дают 422 validation_failed с fields: каждое поле со своими ошибками.

СтатусКодЧто значит
401unauthenticatedНет ключа, ключ неверный или отозван
402limit_reachedСогласия периода закончились: новых боевых ссылок нет
402plan_requiredФункции нужен тариф выше
402profiles_limit_reachedКонфигураций больше, чем позволяет тариф
403account_blockedАккаунт заблокирован: напишите в поддержку
403links_blockedАккаунту нельзя создавать ссылки: напишите в поддержку
403mode_mismatchБоевую ссылку меняют боевым ключом, тестовую тестовым
403live_key_requiredНужен боевой ключ
404not_foundВ вашем аккаунте нет ничего с таким ID
405method_not_allowedЭтот HTTP-метод здесь не разрешён
409link_disabledСсылка отключена, изменить её нельзя
409link_blockedСсылка заблокирована, изменить её нельзя
409idempotency_in_progressЗапрос с этим Idempotency-Key ещё выполняется
409token_usedЭтот токен решения уже проверяли
409export_not_readyВыгрузка ещё готовится
409export_failedВыгрузка не удалась: запустите новую
409consent_not_in_forceЗапись не является действующим согласием: отказ, отзыв или срок истёк
409profile_is_defaultОсновную конфигурацию удалить нельзя
409profile_in_useНа конфигурацию ещё ведут действующие ссылки
410export_expiredФайл больше не хранится: запустите новую выгрузку
422validation_failedЕсть неверные поля: смотрите fields
422destination_blockedАдрес опасный или заблокирован
422idempotency_key_reusedIdempotency-Key уже использован с другим телом
422token_invalidЭто не токен решения вашего аккаунта
422token_expiredТокену решения больше 10 минут
422webhooks_limit_reachedСлишком много действующих вебхуков
429rate_limitedСлишком много запросов: подождите Retry-After
429too_many_exportsСлишком много выгрузок готовится сразу
429daily_limit_reachedНовый аккаунт Free: ссылки на сегодня исчерпаны, ещё с 00:00 UTC
500server_errorСбой на нашей стороне: повторите позже
503unavailableПовторите чуть позже: смотрите Retry-After
Ответ
422 Unprocessable Content
{
  "error": {
    "code": "validation_failed",
    "message": "Some fields are invalid.",
    "fields": {
      "destination": ["The destination must be an absolute http or https URL."]
    }
  }
}

Что делать, если ключ утёк?

Создайте новый ключ на странице «Подключение по API», переключите на него свой сервер и отзовите старый: он сразу перестанет работать. Отзыв ключа не затрагивает ссылки, журнал и вебхуки.

Храните ключи в переменных окружения сервера, никогда в браузере, мобильном приложении или публичном репозитории. Если мог утечь секрет вебхука, отключите этот вебхук в кабинете и создайте новый.

Готовы подключиться?

Зарегистрируйтесь, создайте ключ на странице «Подключение по API» и отправьте первый запрос за несколько минут.

Начать бесплатно