API-ключі
API-ключ - це облікові дані вашого акаунта для Leadgram API. Керуються вони в налаштуваннях: тут ви створюєте ключ, даєте йому ім'я і відкликаєте, коли потрібно. Розберемо, що ключ уміє і чого не вміє, як його створити, як видати йому права, як надіслати ним подію і як його ротувати чи відкликати.
Навіщо потрібні API-ключі
API-ключ дозволяє зовнішньому інструменту чи скрипту репортити конверсії в Leadgram від вашого імені, не передаючи йому логін чи сесійну куку. Це механізм для server-to-server інтеграцій: партнерська мережа, CRM рекламодавця чи власний скрипт надсилають подію в момент депозиту, а не людина клікає в дашборді. Для використання в браузері ключ не призначений.
Створення ключа
- Відкрийте Налаштування → API-ключі.
- Дайте ключу назву, за якою впізнаєте його пізніше, наприклад «Keitaro» чи «скрипт звітів» - це єдине поле у формі.
- Натисніть Створити ключ. Секрет показується рівно один раз, одразу після створення, у блоці для копіювання - скопіюйте його зараз же. Ні таблиця ключів, ні жоден запит більше не покажуть повне значення - зберігаються лише назва і дата створення.

Що ключ може і чого не може
Ключ належить вашому обліковому запису, але робоча область у нього не з'являється сама. Поки ключу жодного разу не зберігали права, він не прив'язаний до жодної області: організацію для нього виводить найраніше живе членство власника, а не та область, що зараз відкрита у вас у дашборді. З однією областю різниці немає, з двома і більше - події поїдуть у найстаршу. Тому в акаунті, де областей більше однієї, видайте ключу права з явно вибраною областю (кнопка Права в рядку ключа) ще до того, як віддасте секрет інтеграції.
Повноцінним доступом до дашборда ключ не стає ні за яких прав:
- Можна з коробки: надсилати події на
POST /api/events. Це єдине, що відкрито ключу без окремого права, і тільки доти, доки права цьому ключу жодного разу не зберігали. - Можна видати окремо: читання звітів і стрічки кліків; приймання конверсій (слаг
events); створення кампаній, оферів, лендингів, воронок і Click Flows, а перемикання статусу - тільки в оферів і лендингів (архівування і повернення з архіву) та в Click Flows (зняття з трафіку й архівування): окремого права на статус у кампаній і воронок немає зовсім; окремим рівнем - правку, публікацію, витрати, правила постбеків і видалення. Кожне право видається конкретному ключу, прив'язане до однієї робочої області і типово вимкнене: у щойно випущеного ключа не позначено нічого. - Не видається нічим: боти та їхні токени, канали, рекламні кабінети, розсилки підписникам, білінг і поповнення, учасники команди, видалення організації, зміна пароля й пошти, відкликання сесій, кастомні домени, тестове надсилання правила постбеку і тестова подія в рекламний кабінет, повторне надсилання вже зробленої доставки, а ще самі права ключа - ключ, здатний розширити себе, це захоплення акаунта, а не зручність. Запит із ключем до
/api/auth/*отримує403завжди, хоч би що власнику ключа було доступно в браузері.
Права відкривають ключу дві поверхні понад приймання конверсій. Перша - читання по HTTP: GET /api/v1/clicks і GET /api/v1/report. Друга - MCP-сервер на POST https://leadgram.org/api/mcp, 25 інструментів, якими розмовний клієнт (Claude, Cursor чи інший хост MCP) створює кампанії, читає звіти й репортить конверсії вашими ж правами. Автентифікація там теж тільки x-api-key, куки дашборда не приймаються, а каталог інструментів однаковий для всіх: відмова за невиданим правом приходить на виклику інструмента і називає, якого саме слага бракує. Параметри, коди відповіді й ліміти обох поверхонь - у Довіднику API.
Виняток для ключів без прав на MCP не поширюється. Ключ, якому права не видавали жодного разу, шле конверсії по HTTP, але той самий ключ у MCP отримає 403 з code: api_key_write_not_granted, поки йому не видали events.
Розподілу прав за учасниками команди в поточному інтерфейсі немає: якщо доступ до інтеграцій потрібен кільком людям чи системам, створіть ключ на кожну окремо - так ви відрізните їх у таблиці і зможете відкликати один, не зламавши інші.
Видача прав
- Відкрийте Налаштування → API-ключі і натисніть Права в рядку потрібного ключа.
- У діалозі Права ключа виберіть Робочу область: ключ працює тільки в ній, і без неї зберігати права нікуди.
- Позначте потрібні слаги в блоках Читання, Запис і Видалення та незворотне.
- Щоб додати право з блоку Видалення та незворотне, введіть
DELETEу полі Підтвердження: цей рівень замкнено окремо. Щоб зняти вже видане, підтвердження не потрібне. - За потреби перемкніть Кампанії на Обмежити кампаніями і виберіть ті, у межах яких ключ працюватиме.
- Натисніть Зберегти права. Блок «Зараз видано» показує результат, а кнопка Зняти всі права знімає видане цілком - разом із прийманням конверсій: після неї ключ не несе нічого, включно з
events, і в стан щойно випущеного ключа, який конверсії ще приймає, не повертається.
Збереження замінює попередні права цілком: це повний перелік того, що ключ уміє, а не додавання до вже виданого. Хочете додати читання і не втратити запис - позначте і те, і те в одному збереженні.
Ось що саме можна позначити. Слаги машинні і не перекладаються: ці самі рядки стоять у редакторі, у кодах відмов і в Довіднику API.
- Читання:
report- зведена воронкаGET /api/v1/report;clicks- посторінкова стрічка кліківGET /api/v1/clicks. - Запис:
campaigns,offers,landings,funnels,click-flows- створення;offers:status,landings:status,click-flows:status- перемикання статусу, тобто архівування і повернення з архіву;events- приймання конверсій. - Видалення та незворотне:
campaigns:update,offers:update,landings:update,funnels:update,click-flows:update- заміна сутності цілком;campaigns:delete,offers:delete,landings:delete,funnels:delete,click-flows:delete- видалення;click-flows:publish- вивід графа в живий трафік;postbacks,postbacks:update,postbacks:delete- створення, правка й видалення правил постбеків;ad-spend- запис рекламної витрати.
По HTTP працює кожне з цих прав, а MCP-інструмент є у всіх, крім одного: у click-flows:update його немає зовсім - парного читання графа за ключем не існує, і розмовному клієнту лишилося б тільки затирати чужий граф наосліп.
Другий рівень читається як «незворотне за наслідками», а не як HTTP-метод DELETE. У ньому лежать заміна оферу й лендинга цілком (не передані поля очищаються, а прочитати поточні значення ключем не можна), публікація графа в живий трафік, створення правила постбеку - воно стріляє на кожній майбутній конверсії на довільну зовнішню адресу - і запис рекламної витрати, у якої порожня сума видаляє рядок. Ярлика «оборотне» в першого рівня при цьому немає: його найгірша гілка - events, а приймання конверсії списує гроші області і надсилає подію в підключений рекламний кабінет, звідки її вже не забрати.
Обмеження за кампаніями доїжджає не до кожного права. Звузити можна читання, приймання конверсій, усе про кампанії та постбеки, запис витрати, видалення воронки і Click Flows, крім click-flows:update. Офери, лендинги, створення й перейменування воронок і заміна графа цілком спільні на всю робочу область за будовою моделі, тож набір, де одночасно позначено таке право і обмеження за кампаніями, не зберігається зовсім: редактор скаже про це окремим рядком, а прямий запит до API отримає 400 з grant_scope_unsupported_resource. Читання під цю перевірку не потрапляє, і звуження до нього застосовується по-справжньому: report і clicks віддадуть тільки вибрані кампанії.
Перше збереження вимикає виняток для ключів без прав, і це найдорожча пастка на цій сторінці. Ключ, якому права не видавали жодного разу, приймає конверсії без усякого гранта. Щойно ви зберегли права - будь-які - працює рівно те, що позначено, а приймання конверсій вимагає позначеного events. Зайшли в діалог по читання звітів, зберегли самий тільки report - і робоча інтеграція, яка щохвилини слала депозити, почала отримувати 403. Редактор попереджає про це в діалозі; позначайте events явно.
Надсилання події: POST /api/events
Ключ передається в заголовку x-api-key:
curl -X POST https://leadgram.org/api/events \
-H "x-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"clickId": "tz4k9m2p1xq7v0b3n8s6d5fg",
"type": "deposit",
"payout": 42.50,
"nonce": "crm-conversion-8813",
"payload": { "telegram_user_id": 123456789 }
}'
Поля тіла:
clickId- обов'язкове. Id кліку, який видав Leadgram: це те значення, що приходить до вас із макроса{click_id}в URL оферу, редиректу кампанії чи лендингу. Клік чужої організації не підійде.type- обов'язкове, одне з:click,land,bot_start,channel_join,join_request,first_dm,miniapp_launch,lead,registration,deposit,ftd,purchase,subscription_renewed,subscription_cancelled,custom_1-custom_8. Приймати тип і виробляти його - різні речі: уclick,landіfirst_dmусередині Leadgram продюсера немає, вони існують лише тому, що ви їх надіслали; а вbot_start,channel_join,join_request,miniapp_launch,purchaseй обохsubscription_*продюсер усередині Leadgram уже є - надішлете їх вручну, поруч з автоматичною з'явиться друга подія. Єдиний виняток -bot_start, і він з умовами: ваш виклик зійдеться з уже записаним стартом, лише якщо несе telegram user id уpayload(без нього - 422,bot_start_missing_telegram_user_id) і в запиті є чим назвати бота, якого запустила людина -payload.bot_usernameчиpayload.bot_id, а якщо їх немає, то бот названогоclickId. У кліку зі звичайної редирект-кампанії бота немає, як і в кліку, чийого бота видалили: такий виклик безbot_username/bot_idпару назвати не може і запишеться окремою подією. Другого списання це вам не коштує - Leadgram списує один раз за людину на робочий простір, а Telegram-акаунт упізнає цю людину завжди, тож дубль безкоштовний, - але в Meta піде другий Lead з іншимevent_id, звести який жодна дедуплікація вже не зможе, і оптимізатор вашої кампанії вивчить, що одна людина сконвертувалася двічі. Подробиці в Подіях і конверсіях.payout- необов'язкове. Виплата за цією конверсією: число від 0 до 1 000 000 (рядок на кшталт"42.50"теж приймається, від'ємні значення відхиляються). Якщо поле не передати, конверсія успадкує «Виплату» оферу, прив'язаного до кліку.nonce- необов'язкове, від 1 до 128 символів. Ключ ідемпотентності: id події виводиться з трійкиclickId+type+nonce, тож повтор того самого запиту не створить другий рядок і не задвоїть ні списання, ні постбеки, ні конверсії в рекламних кабінетах. Зворотний бік: дві справді різні конверсії одного кліку (другий депозит) мають надіслати різнийnonce. Замість поля можна передати заголовокIdempotency-Key- він підхоплюється як запасне джерело того самого значення.payload- необов'язковий об'єкт довільної форми, але три ключі всередині нього платформа розбирає окремо. Заtelegram_user_idрахується білінг і працює дедуплікація постбеків за користувачем.bot_usernameіbot_idстосуються лишеbot_startі називають бота, якого людина справді запустила: @ім'я (зі знаком@чи без) або внутрішній id бота в Leadgram. Обидва необов'язкові, але їх варто надсилати, щойно у вас більше одного бота: без них пара спирається на бота з кліку, а це здогадка, і вона хибна, коли клік прийшов із кампанії з іншим ботом. Ім'я, яке не належить вашим ботам, отримує403, а не тихий відкат до здогадки.
Успішна відповідь - 201 зі створеним рядком події. 400 означає, що тіло не пройшло валідацію, 401 - ключ надіслано, але не прийнято: невідомий, відкликаний, вимкнений чи прострочений. Запит узагалі без заголовка x-api-key до цієї перевірки не доходить: його відбиває раніше 403 із тілом CSRF: Origin header required for mutating requests, і це ознака загубленого заголовка, а не проблеми з кліком. А 403 на самому маршруті приходить у шести різних випадках, і тіло відмови розрізняє їх машинно: клік не знайдено або він належить іншій робочій області - у цієї відмови в тілі одне поле error, ні code, ні hint там немає, і тією самою відмовою без code відповідає bot_start, у якого payload.bot_username чи payload.bot_id називає бота чужої організації; клік лежить поза звуженням ключа за кампаніями або взагалі не прив'язаний до кампанії (code: campaign_scope_forbidden); ключу не видано потрібне право (code: api_key_write_not_granted або api_key_delete_not_granted); власник ключа більше не owner і не admin у цій робочій області (code: role_forbidden), і роль перечитується на кожному виклику - крім ключів, випущених до 2 вересня 2026 року: до них перевірка ролі на POST /api/events по HTTP не застосовується зовсім, тож такий ключ приймає конверсії й після розжалування власника, а лікується це лише випуском нового ключа; права ключа не вдалося розібрати, або в них є рівні запису й вони не називають робочої області (code: api_key_grant_unverifiable); права називають робочу область, а живого членства власника ключа в ній уже немає (code: api_key_org_not_member). Поле code є в усіх, крім першого, а hint із готовою вказівкою, що робити, - в усіх, крім першого та відмови за звуженням кампаній; логуйте code, а не самий лише статус.
Ендпоінт тримає 1800 запитів на хвилину на організацію; понад це приходить 429 із заголовком Retry-After. Тіло понад 1 МіБ відхиляється з 413 ще до розбору: ця стеля стоїть на будь-якому пишучому запиті за ключем. Окремо варто обробити 503 із заголовком Retry-After: 60 (поля code в тілі немає): це не ваш ліміт, а тимчасова недоступність, і для запитів за ключем відмова на аварії завжди закрита - подія НЕ записана, запит треба повторити через названий інтервал. 504 читається так само, але приходить лише в запитів із заголовком Idempotency-Key: обробник не вклався в 55-секундний бюджет, а без цього заголовка обгортка з таймером не вмикається взагалі. 409 буває двох видів: без поля code - запит із тим самим Idempotency-Key ще виконується, повторіть трохи згодом; із code: org_deleted - робочу область видалено. Повтор із тим самим nonce безпечний і саме він є рекомендованою стратегією ретраю: другого рядка від нього не з'явиться.
Ротація і відкликання
Механізму «перегенерувати на місці» немає - секрет ключа фіксований на весь час його життя. Щоб ротувати ключ: спочатку створіть новий, підставте його в інтеграцію, переконайтеся, що події проходять, і лише потім відкличте старий ключ у таблиці, щоб нічого не лишилося працювати на ньому. Відкликання відбувається миттєво - натисніть Відкликати у рядку ключа, і він одразу перестає працювати, без періоду на переїзд, тому спочатку перемикайтесь, потім відкликайте, а не навпаки.
Типові граблі
- Секрет показується один раз, при створенні. Закрили діалог, не скопіювавши, - він втрачений назавжди: відкликайте ключ і створюйте новий.
- Ключ пише конверсії у вашу організацію, тож ключ, що витік, - це чужі події у вашій аналітиці й у ваших списаннях. Що він уміє понад це, залежить від виданих прав. З
postbacksстороння людина заводить правило, яке шле кожну вашу майбутню конверсію на свою адресу, і без обмеження за кампаніями таке правило діє на всі кампанії області, включно з майбутніми; зoffers:updateвона переписує адресу оферу і забирає живий трафік. Гроші та звіти в будь-якому разі ваші: не вставляйте ключ у чат підтримки, публічний репозиторій чи спільний скрипт, а якщо витік - ротуйте і заразом перевірте Постбеки на чужі правила. - Забутий
nonceна ретраях. Без нього повторне надсилання тієї самої події схлопнеться в один рядок, і це добре, але друга справжня конверсія по тому самому кліку без новогоnonceвтратиться так само. - Чужий чи застарілий
clickIdдає403, а не тиху успішну відповідь: подія нікуди не запишеться, і мовчання у звітах означатиме саме це. Але той самий403буває і з інших причин: клік належить не тій робочій області, у яку розв'язався ключ (у ключа без збережених прав це найраніша область власника); ключ звужено за кампаніями, а клік лежить поза звуженням (code: campaign_scope_forbidden); ключу не видано правоevents(api_key_write_not_granted); власник ключа втратив роль owner чи admin (role_forbidden). Розрізняє їх полеcodeу тілі відмови, і його відсутність - теж відповідь:codeнемає рівно тоді, коли клік не знайдено. - Перше збереження прав без позначеного
eventsвимикає приймання конверсій у ключа, який досі працював без прав. Інтеграція починає падати з403одразу, тож зайшли в діалог прав - перевіртеevents, навіть якщо прийшли туди по звіти. - У відкликання немає скасування і немає затримки: будь-яка інтеграція, яка досі використовує старий ключ, одразу починає падати.
- Називайте ключі за тим, куди вони підключені (наприклад «Keitaro prod»), щоб точно знати, який відкликати, коли щось зламалося, а не гадати за голою датою створення.