Интеграция Leadbit с Keitaro: API и постбэк
Интеграция Leadbit с Keitaro в 2026 году: адрес API wapi.leadbit.com, flow_hash, рабочий api.php, постбэки на каждый статус и таблица статусов…

Чтобы подключить Leadbit к Keitaro по API, нужны три вещи: обработчик формы, который отправляет лид на wapi.leadbit.com с ID клика в поле sub1, постбэк Leadbit с макросом {sub1} и соответствие статусов сети статусам трекера. Ниже рабочий api.php, форма, ссылки постбэка и таблица статусов.
Важная оговорка. Публичной документации API у Leadbit нет, описание доступно в кабинете после регистрации. Мы собрали то, что подтверждают открытые источники и проверка адреса API 1 октября 2026 года, а всё неподтверждённое пометили прямо в тексте.
- Leadbit в 2026 году: что изменилось
- Как работает связка Leadbit и Keitaro
- Где взять API-ключ, хеш потока и лендинг
- Параметры API Leadbit
- Форма на лендинге
- PHP-обработчик api.php для Leadbit
- Как проверить отправку
- Постбэк Leadbit в Keitaro
- Шаг 1. Шаблон в Keitaro
- Шаг 2. Постбэки в кабинете Leadbit
- Статусы Leadbit и Keitaro
- Частые ошибки
- Частые вопросы
- Работает ли Leadbit в 2026 году?
- Где документация API Leadbit?
- Что такое flow_hash в Leadbit?
- Какой адрес API у Leadbit?
- Почему не приходят постбэки от Leadbit?
Leadbit в 2026 году: что изменилось
- Сайт работает, но позиционирование другое. leadbit.com теперь называет себя международным performance-агентством, которое соединяет бренды и команды трафика. Вертикали на главной: e-commerce, лидогенерация, финансы, health & beauty, загрузки.
- Регистрация вебмастеров есть: кнопка Sign up, вариант I’m a webmaster. Русской версии сайта нет, адрес leadbit.com/ru/ отдаёт 404.
- API для лидов отвечает. Адрес
https://wapi.leadbit.com/api/pub/new-order/принимает POST и возвращает JSON с ошибками проверки полей. Это подтверждает доступность адреса, но не успешное создание заказа с вашим ключом.
В 2024 году мы работали с Leadbit как с CPA-сетью с инхаус-офферами под разные гео, с нормальной поддержкой и выплатами без задержек. Какие офферы и ставки доступны сейчас, уточняйте у менеджера после регистрации. Если нужна сеть с открытой документацией, посмотрите нашу подборку CPA-сетей для новичков.
Как работает связка Leadbit и Keitaro
- Клик приходит в Keitaro, трекер создаёт subid и показывает ваш лендинг.
- Keitaro подставляет subid в скрытое поле формы вместо
{subid}. api.phpотправляет лид в Leadbit и кладёт subid вsub1.- Leadbit шлёт постбэк на каждое событие: новый лид, подтверждение, отклонение, невалидный и треш. В постбэке
{sub1}возвращает ID клика, и Keitaro пишет конверсию в нужную кампанию.
Если вы льёте на лендинг Leadbit по ссылке потока, API не нужен: хватит постбэка и шаблона Leadbit в трекере. API нужен для своего лендинга или прелендинга с формой. Как выбрать трекер под такую схему, мы разбирали в статье Keitaro, Binom или AIO.
Где взять API-ключ, хеш потока и лендинг
- Зарегистрируйтесь на leadbit.com как вебмастер и войдите в кабинет.
- В разделе «ИСТОЧНИКИ» создайте источник трафика.
- Создайте поток: в «ОФФЕРЫ» нажмите «СОЗДАТЬ ПОТОК» справа от оффера или откройте «ПОТОК» и нажмите «СОЗДАТЬ ПОТОК». Укажите название и источник, в секции «ЛЕНДИНГ» отметьте лендинг и сохраните поток. Порядок шагов взят из инструкции Keitaro для Leadbit.
- Хеш потока для поля
flow_hash: символы в ссылке потока сразу после домена. В справке AlterCPA это четыре символа. - Значение
landing: домен лендинга, который выбран в настройках потока. - API-ключ возьмите в разделе API кабинета. Точное название пункта меню в открытых источниках не подтверждено, при сложностях спросите менеджера.
Параметры API Leadbit
Ключ передаётся не в заголовке, а в конце адреса. Тело запроса обычная форма (application/x-www-form-urlencoded). На JSON сервер отвечает, что обязательные поля не переданы: мы это проверили.
| Поле | Обязательно | Что передавать |
|---|---|---|
| Адрес | да | https://wapi.leadbit.com/api/pub/new-order/API_KEY, метод POST |
flow_hash | да, проверяет API | хеш потока |
referrer | да, проверяет API | адрес, с которого пришёл посетитель |
landing | да по старым инструкциям | домен лендинга из потока |
country | да по старым инструкциям | код страны оффера из двух букв |
name, phone | да | имя и телефон |
sub1 | для постбэка | subid из Keitaro, вернётся макросом {sub1} |
sub2…sub5 | нет | свои метки: источник, кампания, объявление |
email, lastname, address, comment | нет | дополнительные данные клиента |
Что отвечает сервер, мы проверили запросами с заведомо неверным ключом. Без flow_hash и referrer приходит HTTP 400 и {"success":false,"message":"Invalid request parameters","errors":["flow_hash is required","referrer is required"]}. С полями, но с неверным ключом приходит {"status":"fail","message":"An error is occurred. It is not possible to process request."}. Формат успешного ответа публично не описан, поэтому обработчик считает ошибкой HTTP 4xx и 5xx, status=fail и success=false, а всё остальное успехом. Такую проверку нельзя считать подтверждением принятия заказа: неизвестный JSON тоже может пройти условие. До рабочего запуска сверьте положительный ответ с документацией кабинета и найдите тестовый лид в статистике.
Форма на лендинге
Главный файл лендинга назовите index.php или index.html: только в них Keitaro подставляет макросы. Каждой форме поставьте action="api.php", method="post" и добавьте скрытые поля:
<form action="api.php" method="post">
<input type="text" name="name" placeholder="Имя" required minlength="2" maxlength="100">
<input type="tel" name="phone" placeholder="Телефон" required>
<!-- ID клика Keitaro: трекер подставит его вместо {subid} -->
<input type="hidden" name="subid" value="{subid}">
<input type="hidden" name="referrer" value="{referrer}">
<!-- уйдут в sub2-sub4 -->
<input type="hidden" name="utm_source" value="{utm_source}">
<input type="hidden" name="utm_campaign" value="{utm_campaign}">
<input type="hidden" name="utm_content" value="{utm_content}">
<button type="submit">Заказать</button>
</form>Если лендинг лежит не в Keitaro, а на вашем хостинге, допишите к его ссылке в трекере ?subid={subid}, а в форме читайте параметр из адреса с экранированием:
<!-- ссылка на лендинг в Keitaro: https://ВАШ_ЛЕНДИНГ/?subid={subid} -->
<input type="hidden" name="subid" value="<?= htmlspecialchars($_GET['subid'] ?? '', ENT_QUOTES) ?>">PHP-обработчик api.php для Leadbit
Положите файл рядом с index.php и заполните константы API_KEY, FLOW_HASH, LANDING и COUNTRY. Нужен PHP 7.2 или новее с curl и mbstring.
<?php
// api.php: принимает заявку с формы лендинга и отправляет лид в Leadbit по API
declare(strict_types=1);
// ===== Настройки =====
const API_URL = 'https://wapi.leadbit.com/api/pub/new-order/';
const API_KEY = 'API_KEY'; // API-ключ из кабинета Leadbit, дописывается в конец адреса
const FLOW_HASH = 'FLOW_HASH'; // хеш потока: символы в ссылке потока сразу после домена
const LANDING = 'LANDING'; // домен лендинга, выбранного в настройках потока
const COUNTRY = 'ES'; // код страны оффера, две буквы
const SUCCESS_PAGE = 'success.php';
const ERROR_PAGE = 'error.php';
const HTTP_TIMEOUT = 3; // секунды: Keitaro ждёт от PHP локального лендинга не дольше 3 с
const DEDUP_TTL = 86400; // не отправлять тот же телефон повторно 24 часа
const DATA_DIR = __DIR__ . '/data';
function go(string $page, array $query = []): void
{
$query = array_filter($query, 'strlen');
header('Location: ' . $page . ($query ? '?' . http_build_query($query) : ''), true, 303);
exit;
}
function post_str(string $key, int $max = 255): string
{
$v = isset($_POST[$key]) && is_string($_POST[$key]) ? trim(strip_tags($_POST[$key])) : '';
return mb_substr($v, 0, $max);
}
function client_ip(): string
{
// За Cloudflare в REMOTE_ADDR адрес узла Cloudflare, реальный IP посетителя в CF-Connecting-IP
foreach (['HTTP_CF_CONNECTING_IP', 'REMOTE_ADDR'] as $k) {
$ip = $_SERVER[$k] ?? '';
if (filter_var($ip, FILTER_VALIDATE_IP)) {
return $ip;
}
}
return '';
}
function landing_url(): string
{
$https = ($_SERVER['HTTPS'] ?? '') === 'on' || ($_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https';
$host = preg_replace('/[^A-Za-z0-9.:-]/', '', $_SERVER['HTTP_HOST'] ?? '');
return ($https ? 'https' : 'http') . '://' . $host . '/';
}
function post_macro(string $key): string
{
// Keitaro подставляет значения макросов в URL-кодировке: пробел придёт как "+"
return mb_substr(trim(urldecode(post_str($key, 1000))), 0, 255);
}
function referer_url(): string
{
// Откуда пришёл посетитель: поле referrer формы ({referrer} в Keitaro), иначе адрес лендинга
foreach ([post_macro('referrer'), (string) ($_SERVER['HTTP_REFERER'] ?? '')] as $ref) {
if (filter_var($ref, FILTER_VALIDATE_URL)) {
return mb_substr($ref, 0, 500);
}
}
return landing_url();
}
function user_agent(): string
{
return mb_substr((string) ($_SERVER['HTTP_USER_AGENT'] ?? ''), 0, 255);
}
function compact_fields(array $fields): array
{
return array_filter($fields, static function ($v): bool {
return $v !== '';
});
}
function data_file(string $name): string
{
if (!is_dir(DATA_DIR) && @mkdir(DATA_DIR, 0750, true)) {
@file_put_contents(DATA_DIR . '/.htaccess', "Require all denied\n");
}
return DATA_DIR . '/' . $name;
}
function log_event(array $row): void
{
$line = json_encode(['time' => date('c')] + $row, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES | JSON_INVALID_UTF8_SUBSTITUTE);
@file_put_contents(data_file('leads-' . date('Y-m-d') . '.log'), $line . PHP_EOL, FILE_APPEND | LOCK_EX);
}
function mask_phone(string $digits): string
{
return substr($digits, 0, 3) . '***' . substr($digits, -2);
}
// Защита от дублей: в файле хранятся не номера, а их HMAC, чтобы файл не стал базой телефонов
function phone_seen(string $digits, bool $remember = false): bool
{
$fp = @fopen(data_file('phones.json'), 'c+');
if ($fp === false) {
return false; // нет прав на запись: лид не блокируем
}
flock($fp, LOCK_EX);
$list = json_decode((string) stream_get_contents($fp), true);
$list = is_array($list) ? $list : [];
$now = time();
foreach ($list as $k => $t) {
if ($now - (int) $t > DEDUP_TTL) {
unset($list[$k]);
}
}
$key = hash_hmac('sha256', $digits, API_KEY);
$seen = isset($list[$key]);
if ($remember) {
$list[$key] = $now;
}
ftruncate($fp, 0);
rewind($fp);
fwrite($fp, (string) json_encode($list));
flock($fp, LOCK_UN);
fclose($fp);
return $seen;
}
function http_post(string $url, string $body, array $headers): array
{
$ch = curl_init($url);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $body,
CURLOPT_HTTPHEADER => $headers,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_CONNECTTIMEOUT => HTTP_TIMEOUT,
CURLOPT_TIMEOUT => HTTP_TIMEOUT,
]);
$answer = curl_exec($ch);
return [
'code' => (int) curl_getinfo($ch, CURLINFO_RESPONSE_CODE),
'body' => is_string($answer) ? $answer : '',
'error' => curl_error($ch),
];
}
// ===== Обработка заявки =====
if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
go('index.php');
}
if (!function_exists('curl_init')) {
log_event(['result' => 'no_curl']);
go(ERROR_PAGE);
}
$name = post_str('name', 100);
$phone = (string) preg_replace('/[^\d+]/', '', post_str('phone', 32));
$digits = (string) preg_replace('/\D/', '', $phone);
$subid = post_str('subid', 100);
$subid = preg_match('/^[A-Za-z0-9._-]+$/', $subid) ? $subid : ''; // {subid} не подставился = пусто
$thanks = ['name' => $name, 'phone' => $phone, 'pxl' => (string) preg_replace('/\D/', '', post_str('pxl', 32))];
if (mb_strlen($name) < 2 || strlen($digits) < 7 || strlen($digits) > 15) {
go(ERROR_PAGE);
}
if (phone_seen($digits)) {
log_event(['result' => 'duplicate', 'phone' => mask_phone($digits), 'subid' => $subid]);
go(SUCCESS_PAGE, $thanks);
}
$lead = [
'flow_hash' => FLOW_HASH,
'landing' => LANDING,
'country' => COUNTRY,
'name' => $name,
'phone' => $phone,
'referrer' => referer_url(),
'sub1' => $subid, // вернётся в постбэке макросом {sub1}
'sub2' => post_macro('utm_source'),
'sub3' => post_macro('utm_campaign'),
'sub4' => post_macro('utm_content'),
];
$res = http_post(API_URL . rawurlencode(API_KEY), http_build_query(compact_fields($lead)), [
'Content-Type: application/x-www-form-urlencoded',
]);
$answer = json_decode($res['body'], true);
// Успешный ответ публично не описан: ошибкой считаем HTTP 4xx/5xx, status=fail и success=false
$ok = $res['code'] >= 200 && $res['code'] < 300 && is_array($answer)
&& ($answer['status'] ?? '') !== 'fail' && ($answer['success'] ?? true) !== false;
log_event([
'result' => $ok ? 'sent' : 'error',
'phone' => mask_phone($digits),
'subid' => $subid,
'http' => $res['code'],
'curl' => $res['error'],
'answer' => mb_substr($res['body'], 0, 500),
]);
if (!$ok) {
go(ERROR_PAGE);
}
phone_seen($digits, true);
go(SUCCESS_PAGE, $thanks);Перед рабочим запуском. Проверка номера и запись после ответа API выполняются раздельно: одновременные запросы могут пройти оба. Для защиты от гонки нужна атомарная операция или поддерживаемый сетью ключ идемпотентности. Папку data держите вне публичного каталога: создаваемый .htaccess не защищает её в nginx. В журнал попадает ответ API, который может содержать персональные данные или секреты; маскируйте их до записи. Заголовку CF-Connecting-IP доверяйте только от проверенного прокси Cloudflare.
Чем этот код отличается от версии 2024 года из прошлой редакции статьи:
- Проверяет ответ. Старый скрипт отправлял лид и вёл на страницу успеха, даже если Leadbit вернул ошибку. Теперь при ошибке посетитель попадёт на
error.php, а причина останется в журналеdata/leads-ГГГГ-ММ-ДД.log. - Работает по HTTPS. Старый адрес был
http://, через HTTPS тот же адрес отвечает так же. - Не хранит телефоны открытым текстом. Защита от повторной отправки хранит HMAC-хеши номеров 24 часа, а журнал пишет маскированный номер. Зачем вообще отсекать дубли, мы писали в статье про дубли лидов.
- Укладывается в 3 секунды. Это требование Keitaro к PHP локальных лендингов: на все вызовы curl нужны таймауты.
- Берёт реальный IP за Cloudflare из заголовка CF-Connecting-IP.
При успехе скрипт ведёт на success.php и передаёт имя и телефон, чтобы клиент проверил данные. Готовые страницы: «Спасибо за заказ» и страница ошибки. Мы прогнали скрипт против локальной заглушки API (успех, повтор номера, ошибка, HTML 500, ответ дольше 3 секунд, пустой телефон, GET, форма без subid) и против настоящего адреса Leadbit с неверным ключом. Во всех случаях он ведёт на нужную страницу и пишет журнал.
Как проверить отправку
- Загрузите архив с
index.php,api.php,success.phpиerror.phpв Keitaro как локальный оффер. - Создайте тестовую кампанию с одним потоком без фильтров и откройте её ссылку.
- В исходном коде страницы проверьте поле
subid: там должен быть ID клика, а не{subid}. - Отправьте форму и откройте журнал в папке
data. При ошибке там будет полный ответ Leadbit. - Найдите лид в статистике Leadbit и убедитесь, что у клика записан
sub1.
Постбэк Leadbit в Keitaro
Шаг 1. Шаблон в Keitaro
В Keitaro откройте «Партнерские сети», нажмите «Создать», в поле «Из шаблона» введите Leadbit и сохраните. Так выглядел шаблон в нашем трекере в 2024 году:

Ссылка из этого шаблона с одним общим постбэком и обучением статусов:
https://ВАШ_ДОМЕН/POSTBACK_KEY/postback?subid={sub1}&payout={cost}&status={status}¤cy=usd&tid={id}&offer_landing={landing}&flow={flow}&lead_status=new&sale_status=confirm&rejected_status=reject,decline,invalid,trash&from=leadbit.comШаг 2. Постбэки в кабинете Leadbit
В кабинете Leadbit у постбэка отдельные поля под каждое событие: при новом лиде, при подтверждении, при отклонении, на невалидный лид, на треш лид и при новой регистрации. Поэтому проще всего в каждое поле поставить готовый статус Keitaro. Обучение статусов тогда не нужно:
Postback при новом лиде:
https://ВАШ_ДОМЕН/POSTBACK_KEY/postback?subid={sub1}&status=lead&payout={cost}¤cy=usd&tid={id}
Postback при подтверждении лида:
https://ВАШ_ДОМЕН/POSTBACK_KEY/postback?subid={sub1}&status=sale&payout={cost}¤cy=usd&tid={id}
Postback при отклонении, на невалидный и на треш лид:
https://ВАШ_ДОМЕН/POSTBACK_KEY/postback?subid={sub1}&status=rejected&payout={cost}¤cy=usd&tid={id}ВАШ_ДОМЕН и POSTBACK_KEY возьмите в Keitaro в разделе «Настройки», пункт «Postback URL». Поле «при новой регистрации» для нутры оставьте пустым. В tid уходит ID лида в Leadbit: тогда новые статусы одного лида обновляют его конверсию, а два лида с одного клика не перезаписывают друг друга. Так работает параметр tid по справке Keitaro.

Где именно лежат эти поля в 2026 году, публично не описано. По скриншоту 2024 года это «Редактировать глобальный постбэк», по инструкции Keitaro поля «НАСТРОЙКА ПЕРЕДАЧИ СТАТИСТИКИ» есть и в настройках потока, а справка Voluum указывает путь Profile, Global Postback. Выберите один вариант, глобальный постбэк или поля в потоке, чтобы потом не искать, откуда пришла конверсия.
Макросы постбэка Leadbit по шаблонам трекеров AnyTrack и Voluum: {sub1}…{sub5}, {cost} (выплата), {currency}, {status}, {id}, {flow}, {landing}, {offer}, {ip}, {date}.
Статусы Leadbit и Keitaro
| Событие в Leadbit | Значение status в шаблоне Keitaro | Что ставить в отдельное поле | Конверсия в Keitaro |
|---|---|---|---|
| Новый лид | new | status=lead | Lead |
| Подтверждение | confirm | status=sale | Sale |
| Отклонение | decline, reject | status=rejected | Rejected |
| Невалидный лид | invalid | status=rejected | Rejected |
| Треш | trash | status=rejected | Rejected |
| Новая регистрация | не указано | оставить пустым | не нужна для нутры |
Частые ошибки
- Ответ «flow_hash is required», хотя поле есть. Лид ушёл в JSON. Leadbit ждёт обычную форму, как в коде выше.
- Ответ «It is not possible to process request». Неверный ключ, хеш чужого потока или лендинг не из этого потока.
- В Keitaro «Click for subid REPLACE not found». Leadbit не получил subid: в форме нет поля с
{subid}или лендинг открыт не через трекер. - «Conversion type not found». В постбэк пришёл статус, которого трекер не знает. Добавьте его в
lead_status,sale_statusилиrejected_status. Остальные коды ошибок разобраны в справке Keitaro. - Тестовый постбэк не создаёт конверсию. В тестовых постбэках сети не передают настоящий subid. Проверяйте реальным лидом.
- Файл leads.txt со старым скриптом. В нём телефоны открытым текстом в папке лендинга. Удалите его с сервера.
Частые вопросы
Работает ли Leadbit в 2026 году?
Да. Сайт leadbit.com открывается, регистрация вебмастеров есть, адрес API отвечает. Сама компания теперь называет себя performance-агентством, а не CPA-сетью.
Где документация API Leadbit?
Только в кабинете после регистрации. Открытой документации нет, поэтому сверяйте поля с разделом API кабинета или у менеджера.
Что такое flow_hash в Leadbit?
Это хеш потока: символы в ссылке потока сразу после домена. Без него API отвечает ошибкой «flow_hash is required».
Какой адрес API у Leadbit?
https://wapi.leadbit.com/api/pub/new-order/, к нему в конце добавляется ваш API-ключ. Метод POST, данные обычной формой.
Почему не приходят постбэки от Leadbit?
Проверьте, что ссылки стоят во всех полях постбэка, а в лиде записан sub1. Сеть может отправить постбэк не сразу, а после обработки лида колл-центром.



