Постбеки: приём конверсий от партнёрских сетей
Защита от «нулевого платежа без сигнала»
Если в маппинге эндпоинта не указан параметр суммы или сеть присылает деньги под именем,
которого маппинг не ждёт, конверсия с выплатой 0 при ответе сети 200 OK осталась бы
незамеченной до сверки с личным кабинетом сети. Поэтому на каждый постбек с итоговой
суммой 0 (уже ПОСЛЕ того, как найден клик и известен его оффер) проверки идут по
приоритету — от самого надёжного сигнала к самому неявному:
- При создании/изменении маппинга пустое поле
sumне даёт сохраниться без явного флага подтверждения (query-параметрallow_no_sum=1) — обычное сохранение через форму/API с пустымsumвернёт ошибку валидации. - Деньги видны в другом параметре запроса. Если прочитанный маппингом параметр суммы
пришёл нулём (
payout=0.00), а рядом лежит непрочитанный параметр, похожий на сумму (по вхождению подстроки:sum,amount,payout,revenue,payment,price,value,commission,reward,profit,income,cost) с ненулевым значением (amount=12.50) — конверсия уходит в карантинunread_sum_paramс перечнем этих параметров. Свою цифру за оператора не выбираем — обе интерпретации могут быть верны, это ручной разбор. - Параметр суммы не настроен/отсутствует в запросе, но похожий на деньги параметр
есть. Тот же карантин
unread_sum_param— сеть, похоже, прислала выплату под именем, не подключённым в маппинге. - Ничего похожего на сумму в запросе нет вообще. С точки зрения кода это неотличимо
от «у события действительно нет выплаты» (например,
leadбез депозита) и от «сеть назвала параметр словом, которого нет в списке хинтов выше» — это и есть тот самый редкий случай, который раньше проходил молча. Теперь выбираются условия по ГЕО клика, а при отсутствии строки страны — общие условияoffers.*. Фиксированная частьcpa/cpl/hybridподставляется только за указанную в условиях цель и при ненулевомpayout; валюта берётся из тех же условий (при пустой — из оффера). У общих условий цели нет, поэтому сохраняется прежнее правило:cplплатит заlead,cpa— заapproveилиftd, общийhybridничего не подставляет. Конверсия помечается_sum_source=offer_default(видно вraw), публикуется алертpostback_sum_offer_defaultи растёт метрикаinotrack_postback_sum_offer_default_total. Подстановка заметна и требует проверить маппинг сети.revshareничего не подставляет: процент справочный, фактический доход приходит отдельными постбекамиrebill/commission. Уhybridподставляется только фиксированная часть за её цель; процент от депозита трекер не вычисляет. - Последний рубеж, независимо от пп. 2–4: подтверждённая конверсия с нулевой
выплатой при ненулевой фиксированной части действующих условий за эту цель
вызывает алерт
postback_approved_zero_payoutи рост метрикиinotrack_postback_approved_zero_payout_total. Ноль наrevshareи на событиях гибрида вне цели фиксированной части не считается дефектом. Алерты содержат ГЕО клика и действующую модель ставки. Запись не блокируется: сеть может быть права насчёт нуля, но случай становится видимым сразу. Сумма, присланная сетью, всегда главнее справочных условий.
Что до сих пор не покрыто: подстановка offer_default (п. 4) — это справочная выплата
оффера, а не то число, которое реально прислала сеть за КОНКРЕТНУЮ конверсию (для CPA с
фиксированной ставкой это обычно одно и то же, но не гарантированно — например, если сеть
платит по факту меньше из-за собственных корректировок). Для revshare и переменной
части hybrid без явного денежного параметра ноль пишется без подстановки: угадывать
доход игрока нельзя. Проверяйте вручную: после подключения новой сети отправьте
тестовый постбек (см. ниже) и сверьте сумму в ответе с тем, что реально прислала сеть.
Формат входящей ссылки
GET/POST https://<трекер-домен>/pb/{token}?clickid={clickid}&status=approve&sum=25&txid=123
{token}— свой токен на каждый postback-эндпоинт (не путать с токеном потока). Один эндпоинт = один физически подключённый провод от конкретной сети.- Метод —
GETилиPOST(в т.ч.application/x-www-form-urlencodedв теле). Если один и тот же параметр пришёл и в query, и в теле — побеждает тело. - Имена параметров (
clickid,status,sum,txid...) настраиваются в маппинге эндпоинта под конкретную сеть — это не фиксированный список, а то, что вы укажете. - Опционально — allowlist IP/CIDR для эндпоинта: если задан, запросы не из списка
получают
403.
Ответ почти всегда 200 OK, даже если постбек в итоге уйдёт в карантин или будет подавлен
дедупом — это осознанное решение: карантин и дедуп — наши внутренние состояния, а не повод
запускать у сети ретрай-шторм по уже принятому запросу.
⚠️ Важно про момент ответа: /pb/{token} — быстрый синхронный приёмник. Он делает
только офлайн-проверку (парсится ли маппинг, есть ли clickid) и сразу кладёт постбек в
персистентную очередь Postgres, отвечая сети 200 accepted — тело "accepted". Собственно
обработка (дедуп, поиск клика, проверка суммы на карантин, запись конверсии) выполняется
асинхронно фоновым воркером (опрос очереди каждые 500 мс). Поэтому в теле немедленного
ответа НЕ будет буквального duplicate или quarantined: click_not_found — это исходы,
которые нужно смотреть в списке карантина (GET /api/internal/postback/quarantine, либо
через прокси GET /api/v1/postback/quarantine) или в логе очереди приёма, а не в ответе на
сам HTTP-запрос. Синхронно в ответе видны только quarantined: no_clickid,
quarantined: mapping_error и quarantined: bad_sum — это единственные проверки, которые не
требуют похода в БД.
Отсутствие клика при этом не приводит к карантину немедленно: если клик ещё не успел
доехать из буфера клик-пути в ClickHouse, воркер ретраит с бэкоффом (до 20 попыток) и
уводит в карантин click_not_found только на последней — то есть окончательный статус
постбека может стать известен через несколько секунд после ответа 200 accepted, не в
момент самого запроса.
Статусная модель конверсии
Порядок стадий воронки: reg → lead → approve/reject → ftd → dep → rebill
(approve и reject — одна и та же стадия принятия решения по лиду).
Каждый постбек с новым статусом обновляет ту же конверсию, а не создаёт дубль —
история изменений статуса пишется отдельно (кто, когда, старый статус → новый).
Если новый статус «откатывается назад» по порядку воронки (например, пришёл lead
после ftd) — запись не блокируется (сеть — источник истины по своим данным), но это
помечается как нетипичный переход, полезно при отладке маппинга новой сети.
Отдельно от goal (reg/lead/approve/...) хранится свёрнутый трёхзначный статус:
pending / approved (approve, ftd, dep, rebill) / rejected — им пользуются отчёты,
которым нужна «подтверждённая выручка» независимо от конкретного шага воронки.
Дедупликация
Идемпотентность — по комбинации (сеть, clickid, goal, txid): при повторном
поступлении того же набора конверсия не пишется повторно. Сама проверка дедупа — часть
асинхронной обработки (см. предупреждение выше), поэтому HTTP-ответ на дублирующий запрос
всё равно 200 accepted, а не 200 duplicate — распознать дубль по немедленному ответу
нельзя, только по логу обработки. Ключ дедупа живёт в Redis 30 дней. Если сеть присылает повторные постбеки по
одному и тому же лиду с ростом статуса (lead → approve → ftd), каждый новый goal
— это новая точка дедупа, старые статусы не блокируют новые.
Постбек без клика / без clickid
- Нет параметра clickid вообще → карантин
no_clickid. - Есть clickid, но клика с таким ID нет в базе (устарел, опечатка на стороне сети) →
карантин
click_not_found. Если клик просто ещё не дописался в ClickHouse — это не карантин с первой попытки: фоновый воркер ретраит с бэкоффом (см. предупреждение выше про асинхронную обработку) и уводит в карантин только когда попытки исчерпаны. - Параметр статуса не сопоставлен ни одному значению в словаре маппинга и не похож на
наши стандартные значения (
reg/lead/approve/reject/ftd/dep/rebill) → карантинmapping_error. - Сумма пришла, но это не число (отрицательная, нечисловая или неоднозначная вроде
1,234) → карантинbad_sum. - Сумма пришла, но не читается маппингом (см. раздел выше) → карантин
unread_sum_param.
Карантинные постбеки не теряются: они складываются в отдельную таблицу с исходными параметрами запроса, и оттуда конверсию можно доматчить руками на нужный clickid.
Окна атрибуции
На каждом оффере настраивается срок жизни клика для привязки конверсии
(attribution_hours) и модель — last_click (по умолчанию) или first_click. Если
attribution_hours не передан или равен 0 в POST /api/v1/offers, оффер получает
значение по умолчанию — 720 часов (30 дней). Конверсия, пришедшая позже окна, всё равно
записывается, но с пометкой «вне окна атрибуции» и в атрибутированные не попадает.
Тестовый постбек
Есть отдельный dry-run эндпоинт, который прогоняет маппинг и все проверки (включая поиск клика и детект «сумма не читается»), но не делает ни одной записи — удобно проверить новый маппинг сети перед тем, как отдавать ей боевую ссылку.
Пресеты сетей
Готовые (стартовые) маппинги параметров и словари статусов есть для: Leadgid,
Pampadu, Unicom24, Guruleads, Leads.su, PIN-UP Partners, 3snet, Vavada, RevenueLab, Zeydoo,
RakeCore/Rollix, AppMetrica, CityAds, Admitad — плюс custom для произвольного маппинга. Все они
есть в выпадающем списке формы подключения в панели. Подключения, заведённые раньше, пресет не
меняет: у каждого свой сохранённый маппинг.
⚠️ Важно: имена параметров и значения статусов в пресетах — типовые для рынка CPA-сетей на момент написания, но не сверены построчно с актуальной документацией каждой конкретной сети. Пресет — это отправная точка для заполнения формы, а не гарантированно рабочая интеграция «из коробки». При подключении сети маппинг нужно свериться по её актуальной документации и при необходимости поправить (маппинг эндпоинта полностью переопределяет любое поле пресета).
Пример полей пресета (PIN-UP Partners): clickid → clickid, status → status,
sum → sum, txid → txid, словарь статусов registration/reg → reg,
qualified → lead, ftd → ftd, deposit/repeated_dep → dep, валюта по умолчанию USD.
Полный список полей и словарей для остальных пресетов — в ответе
GET /api/v1/postback/presets.
Сверка с документацией сетей 04.10.2026:
- Leadgid — сверен по справке переменных на экране «Постбеки» кабинета вебмастера
my.leadgid.com (открытого help-центра нет: help.leadgid.com закрыт). Наш clickid — в
aff_subссылки оффера («SubID 1 указанный вами в трекинг ссылке»), постбек возвращает его{aff_sub}. Статусы{status}:pending→ lead,approved→ approve,rejected→ reject (старые ключиlead/hold/trashпресета оставлены). Сумма{payout}, валюта{currency}(без неё — RUB), txid{lead_id}(один на все смены статуса лида), внешний id оффера{offer_id}, цель{goal_id}— в доп. полеgoal_id. Переходpending→rejectedLeadgid постбеком не шлёт (так написано в кабинете) — такие отказы видны только в сверке со статистикой сети. Открытой документации API нет (Swagger — только в кабинете), отдельного адаптера сверки нет. - Admitad — сверен по статье «Postback URL» базы знаний Admitad
(https://admitad.useresponse.com/knowledge-base/article/postback-url_5). Постбек настраивается в
кабинете: Tools → Postback URL, событие «Action». Макросы — в тройных квадратных скобках.
Наш clickid — в
subid4партнёрской ссылки (…/g/…/?subid4={clickid}): Admitad отводитsubid4под click id и transaction id, аsubid…subid3остаются под метки источника. Постбек возвращает его[[[subid4]]]. Статус[[[payment_status]]]:new→ lead,approved→ approve,declined→ reject,pending(подтверждённое действие вернули в холд) → lead. Сумма[[[payment_sum]]](заработок вебмастера), валюта[[[currency]]](валюта программы; без неё — RUB), txid[[[action_id]]](один на все смены статуса действия), внешний id оффера[[[offer_id]]]. В доп. поля уходят[[[order_id]]],[[[order_sum]]],[[[type]]](lead/sale) и[[[reward_ready]]]— признак «готово к выводу»; на цель он не влияет. Имена параметров пресета совпадают со стандартными именами Admitad, поэтому подходит и «Simple mode» кабинета (полный набор параметров), и «Advanced mode». - CityAds — сверен по разделу «Conversion Postback» документации вебмастера
(http://userdocs.cityads.com/docs/udocs/en/latest/content/tools/ConversionPostback.html).
Макросы — в фигурных скобках. Наш clickid — в
xidссылки, постбек возвращает его{xid}. Статус{status}:open→ lead,approved→ approve,rejected→ reject. Сумма{payout}(комиссия вебмастера, разделитель — точка), валюта{payout_currency}(валюта аккаунта вебмастера; в примере документации приходитRUR— приём считает его рублём), txid{cpl_id}(один у лида и продажи одного заказа), внешний id оффера{offer_id}. В доп. поля уходят{action_type}(CPL/CPA) и{order_amount}. Сумма, валюта и статус заполняются только в постбеке продажи (CPS); в постбеке лида (CPL) сумма и валюта пустые — конверсия ляжет лидом без денег. Постбек создаётся в кабинете (Tools → Conversion Postback) и проходит модерацию CityAds. - Guruleads — открытой документации по ссылке, макросам и статусам не найдено (справка по
постбекам только в кабинете). Пресет
guruleads— прежняя отправная точка, не сверен. - Saleads — не найдено: сеть принимает в ссылке любые метки (saleads.pro/tools, «Субаккаунты»),
но макросы постбека и статусы подсказываются только в кабинете («Инструменты → Глобальный
постбек», отдельная ссылка на каждое событие). Пресета нет — подключение своим маппингом
(
custom), статус в каждой из ссылок кабинета задаётся вручную.
Pampadu, Unicom24 и Leadgid: готовая ссылка для кабинета сети
Для этих сетей есть справочник макросов (GET /api/internal/postback/networks). Кнопка «Для сети» в списке подключений собирает
строку по фактическому маппингу подключения (GET .../endpoints/{id}/network-template).
Для Leadgid строку пока отдаёт только API: в панели кнопка показывается для Pampadu и Unicom24,
ссылку Leadgid собрать по таблице ниже:
| Сеть | Где в кабинете | Ссылка |
|---|---|---|
| Pampadu | Вебмастеру → Postback, GET | https://<домен>/pb/<token>?clickid={sub1}&status={status}&sum={amount}&order_id={order_id} |
| Leadgid | Инструменты → Постбеки → Глобальный → Создать, GET, события «Новая конверсия» и «Обновление статуса» | https://<домен>/pb/<token>?clickid={aff_sub}&status={status}&payout={payout}&lead_id={lead_id}&offer_id={offer_id}¤cy={currency}&goal_id={goal_id} |
| Unicom24 | Инструменты → Postback → Создать, «Глобальный», GET, статусы «В работе», «Подтвержден», «Отклонен», «Оплачено» | https://<домен>/pb/<token>?click_id={click_id}&conv_status={conv_status}&payment_sum={payment_sum}&redirect_id={redirect_id}&offer_id={offer_id}&is_paid={is_paid}&sub_id1={sub_id1}&status={status} |
Статусы: Pampadu Pending, Check → lead (холд), Approved → approve, Declined → reject —
сверено 22.10.2026 с подсказками авторизованной формы «Новый постбэк»; clickid в {sub1} и order_id (id заявки, единица дедупа — им,
а не суммой/статусом/offer_name) из той же справки тоже подтверждены. Unicom24 conv_status:
pending → lead, approved → approve, declined → reject. Статус перехода
{status} (receive/accept/…) и {is_paid} пишутся в доп. поля конверсии. Id заявки в
переменных Unicom24 нет, поэтому txid — хеш перехода {redirect_id}: он один на все смены
статуса заявки.
Pampadu: проверено 22.10.2026 в авторизованной форме «Новый постбэк», без сохранения
и отправки теста. Сумма — {amount}, Gross — {cost}; {click_id} — идентификатор
клика Пампаду, а clickid трекера возвращается через {sub1}. Валюта и фактическая
выплата по реальной конверсии не проверены: отчёт за 7 дней пуст.
| Переменная | Смысл в форме |
|---|---|
{offer_id} |
Уникальный идентификатор оффера |
{offer_name} |
Наименование оффера |
{click_id} |
Уникальный идентификатор перехода на стороне Пампаду |
{order_id} |
Уникальный идентификатор конверсии |
{status} |
Статус конверсии |
{conversion_time} |
Время получения конверсии (подсказка; подпись строки — «Статус конверсии») |
{amount} |
Сумма по конверсии |
{cost} |
Сумма Gross |
{promo} |
Промокод |
{goal_id} |
ID цели |
{goal_name} |
Имя цели |
{deposit} |
Количество депозитов |
{sub1} |
Переданный SubID 1 (clickid трекера) |
{sub2} |
Переданный SubID 2, кнопка «Добавить sub» |
{sub3} |
Переданный SubID 3, кнопка «Добавить sub» |
{sub4} |
Переданный SubID 4, кнопка «Добавить sub» |
{sub5} |
Переданный SubID 5, кнопка «Добавить sub» |
Сверка с отчётом сети и дозаливка
Публичного API статистики у Pampadu и Unicom24 нет: обеим сетям конверсии сверяются либо
загруженным файлом (ниже), либо (если сеть подключена источником «Кабинет (веб)» — см.
подраздел «Кабинет (веб)» дальше) — построчным отчётом, который трекер сам забирает из
кабинета партнёра. Вкладка «Сверка с сетью» (только admin) принимает
выгрузку конверсий из кабинета: CSV (;, , или табуляция, UTF-8 или Windows-1251) или XLSX,
до 10 МБ и 50 000 строк. Колонки сопоставляются с полями clickid, статус, ID заявки,
вознаграждение, дата, ID офера и валюта. Маппинг подбирается по заголовкам и сохраняется на
подключении.
Каждая строка сравнивается с действующим решением по (clickid, txid) в ClickHouse за окно до
30 дней. Возможные итоги: missing (конверсии у нас нет), status_behind (у нас лид, у сети
решение), status_conflict, payout_diff, ours_ahead, ours_only, ok, skipped
(нет clickid, строка старше окна, клика нет, статус не распознан, повтор строки). Если ни один
ID заявки из файла по клику не совпал ни с одной нашей транзакцией этого клика, строка получает
status_conflict, а не missing: скорее всего колонкой «ID заявки» выбран не тот идентификатор,
что приходит постбеком, и дозаливка задвоила бы конверсию (у Белки ключ it:{clickid}:{order_id}).
Отставший статус дозаливается в ту же транзакцию, с txid нашего решения. «Проверить»
только строит отчёт. «Дозалить» ставит missing и status_behind в обычную очередь приёма
постбеков с параметрами в именах маппинга подключения. Дальше они идут обычным путём:
словарь статусов, дедуп, антифрод, курс, запись, вебхук conversion. Отличия дозаливки:
- конверсия датируется датой из файла, обрезанной в [клик, сейчас];
- капы её не считают;
- исходящие постбеки в источники трафика по умолчанию не уходят (переключатель в форме);
- в событии и вебхуке
conversionесть полеOrigin: "reconcile". Остальные поля не менялись.
Служебные параметры _it_* в строке очереди ставит только сверка. Из запросов сетей на /pb
они вырезаются. Повторная загрузка того же файла ничего не дублирует. Прогоны и их строки
хранятся в postback_reconcile_runs, агрегат пишется в network_reconcile для сверки финансов.
Сверка по API: Admitad, CityAds, Leads.su
У сетей с API конверсий сверка идёт сама, без файла. Включается в настройках подключения сети
(источник «API»), поле «Сверка конверсий по API» (config.api_reconcile). По умолчанию стоит
report. Планировщик интеграций раз в api_reconcile_interval_min минут (по умолчанию 60,
от 15 до 1440) забирает конверсии сети за последние api_reconcile_days дней (по умолчанию 7,
не больше 30). Дальше строки идут в ту же сверку, что у файла, с подключением постбеков этой
сети у рекламодателя: пресет cityads, leads_su, admitad или config.reconcile_preset
(подключение Admitad, заведённое до появления пресета, обычно custom — его и укажите).
| Сеть | Метод API | clickid | ID конверсии (txid) |
|---|---|---|---|
| Admitad | GET /statistics/actions/ |
метка clickid_param; если не задана — subid, а при пустом subid — subid4 |
action_id |
| CityAds | GET …/xml/orderstatistics/{from}/{to}, по дате конверсии; асинхронный отчёт (204 + request_id) дочитывается |
xid |
submissionID; config.reconcile_txid = order берёт orderID, none отключает |
| Leads.su | GET conversions, все статусы |
метка clickid_param (по умолчанию aff_sub1) |
id; config.reconcile_txid = none отключает |
Статусы адаптер переводит в pending/approved/rejected. Словарь пресета превращает их в
значения макроса постбека, например open у CityAds или accepted у Leads.su. Режимы:
report: только отчёт в истории сверок подключения, с подписью «сверка API · <сеть>»;backfill: отчёт плюс дозапись. Потерянный постбек (missing) и отставший у нас статус (status_behind) ставятся в очередь приёма сOrigin: "reconcile", так же, как кнопка «Дозалить». Включается только после отчёта с совпадением txid, см. ниже;off: сверка выключена.
Повторный прогон ничего не дублирует. Поздний постбек с тем же txid отсекает дедуп (сеть,
clickid, goal, txid). Конверсии моложе api_reconcile_grace_min минут (по умолчанию 120)
ждут следующего прогона, потому что их постбек мог ещё не дойти. Агрегат за период пишется в
network_reconcile, это раздел «Финансы → Сверка».
Ссылка оффера Admitad из каталога — gotolink программы с subid4={clickid}
(config.clickid_param меняет метку: subid, subid1…subid4). Ссылку, которую оператор
правил руками, импорт не трогает — например subid={clickid} у прежних подключений остаётся, и
сверка по-прежнему читает clickid из subid. Если subid занят своей меткой источника, а
clickid идёт в subid4, задайте clickid_param = subid4 явно. Генератор deeplink Admitad
(ссылка на конкретную страницу магазина, admitad.Client.Deeplink) в импорт каталога не
подключён: каталог не знает целевую страницу, а запрос на каждую программу при каждой
синхронизации — лишняя нагрузка на API. Ссылку на страницу пока берут в кабинете Admitad
(генератор Deeplink) и вставляют в оффер с subid4={clickid}.
Каждый прогон записывается в журнал загрузок интеграции (тип stats). Там видно число строк, отложенных свежих строк и итог сверки.
Совпадение txid и включение дозаписи
Дозапись кладёт конверсию с txid из API сети. Если это не тот id, что сеть шлёт в постбеке,
поздний постбек не попадёт в дедуп и ляжет второй конверсией с выплатой. Документация CityAds не
говорит, какой id статистики совпадает с {cpl_id} постбека. Leads.su может не передавать id
конверсии в постбеке вовсе. Поэтому каждый прогон считает долю совпадения txid:
- M: строки сети, по click id которых у нас есть конверсия;
- N: из них строки, чей txid равен txid нашей конверсии этого клика.
Панель показывает у интеграции «совпадение txid: N из M (X %)»: на странице импорта и в форме
подключения рядом с режимом сверки. В журнале прогона это поля txid_compared, txid_matched,
txid_alt (с каким полем id из API совпал наш txid), txid_advice. Вторая конверсия клика с
потерянным постбеком расхождением не считается, если остальные конверсии клика сошлись.
Включить backfill в панели и по API (PUT /integrations/{id}) можно, только если последний
прогон в режиме report не старше 7 дней показал совпадение от 95 % при M от 20 и с тех пор не
менялись reconcile_txid и reconcile_preset. Иначе ядро отвечает 409 с причиной и цифрами.
Смена reconcile_txid или reconcile_preset при включённой дозаписи проверяется так же.
Проверить заранее: GET /integrations/{id}/reconcile-check.
Администратор может включить дозапись без подтверждения: флажок «Я понимаю риск дублей» в форме,
в API поле accept_duplicate_risk: true. Такое включение пишется в audit_log с действием
integration.api_reconcile_backfill_forced и текстом отказа. Обычное включение по отчёту пишется
с действием integration.api_reconcile_backfill.
Маппинг сверка сама не меняет. При низком совпадении отчёт подсказывает, что сделать:
| Что видно в отчёте | Что сделать |
|---|---|
CityAds: txid постбека совпадает с orderID, а не с submissionID |
reconcile_txid = order, дождаться нового отчёта |
| Наши конверсии без txid: постбек не передаёт id конверсии | добавить макрос id в ссылку постбека ({cpl_id} у CityAds, id конверсии в action_id у Leads.su) либо reconcile_txid = none |
| Не совпало ни одно поле id из API | проверить, какой макрос стоит в параметре txid ссылки постбека; дозапись не включать |
Кабинет (веб): Unicom24, Pampadu
У сетей без публичного API есть источник подключения «Кабинет (веб)» (config.source = "web"
на интеграции): вместо ручной выгрузки файлом трекер сам входит в кабинет партнёра под
реквизитами оператора и внутренним JSON-API кабинета тянет и каталог офферов, и построчный
детальный отчёт конверсий — тот же формат, что у сверки файлом выше, только без файла.
Реквизиты входа задаются в панели, на подключении интеграции сети, и хранятся зашифрованными
(network_web_sessions, тем же ключом, что и секреты интеграций, INOTRACK_INTEG_ENC_KEY) —
наружу отдаётся только статус сессии (есть/нет, вход логином, cookie или токеном, до когда действует,
когда проверена последний раз), сами пароль, cookie и токен по API не читаются:
| Сеть | Поля формы |
|---|---|
| Unicom24 | логин и пароль партнёра или cookie сессии кабинета |
| Pampadu | pampadu_login + pampadu_password или pampadu_session_token (значение usrtoken из localStorage браузера, без префикса Bearer) |
Каталог офферов в режиме «Кабинет (веб)» синхронизируется по расписанию
config.sync_interval_min (15–60 минут, по умолчанию 30 — чаще, чем у источника «API»).
Построчная сверка конверсий (раздел выше) по кабинету — режим config.web_reconcile:
off— не сверять;report(по умолчанию) — только отчёт, без записи: первый прогон стоит посмотреть глазами, прежде чем доверять ему дозапись денег;backfill— отчёт плюс дозаливка потерянных (missing) и отставших (status_behind) конверсий в обычную очередь приёма постбеков — так же, как кнопка «Применить» у сверки загруженным файлом.
Для Pampadu дозаливка из кабинета отключена: backfill всегда выполняется как report,
без создания конверсий. 22.10.2026 живое чтение подтвердило каталог (542 оффера,
414 доступны аккаунту) и пустой отчёт за 7 дней. Идентификаторы и суммы непустых строк
отчёта ещё не проверены. Процентные ставки хранятся в примечании как revshare,
без подстановки процента в фиксированную выплату RUB. CSV/XLSX остаётся запасным путём.
Период прогона — config.web_reconcile_interval_min (15–1440 минут, по умолчанию 60):
детальный отчёт кабинета за 30 дней — не лёгкий запрос, чаще 15 минут его дёргать смысла нет.
Строки сверяются с решением по (clickid, txid) тем же ReconcileRows, что и у файла; подключение
постбеков сети у рекламодателя для сверки ищется по пресету (unicom24/pampadu). Повторный
прогон ничего не дублирует.
Режим «Кабинет (веб)» заменяет собой ручную загрузку файла, а не добавляет официальный API сети — публичного API статистики у Pampadu и Unicom24 как не было, так и нет.
Антифрод конверсий
Всплеск конверсий считается в Redis ZSET по подсети и отпечатку устройства:
точное скользящее окно с включёнными границами, без текущего постбека.
Повтор сети/clickid/goal/txid не увеличивает счётчик; тестовые конверсии исключены.
При недоступном или пустом Redis burst временно не срабатывает, приём продолжается.
CR — конверсии из conversions FINAL / сумма кликов из stats_hourly без FINAL.
Окно знаменателя округлено до часа; реплей WAL может увеличить сумму MV.
Оба эффекта снижают CR и ложные срабатывания; тестовые клики исключены MV.
Каждая входящая конверсия проверяется на признаки фрода и, при срабатывании, помечается
флагом suspicious с причиной (в отдельном отчёте, не исключается из базы автоматически —
решение остаётся за оператором):
- конверсия пришла без соответствующего клика в базе;
- аномально быстрый переход клик → конверсия;
- всплеск конверсий с одной подсети/устройства;
- CR источника выше правдоподобного порога;
- конверсия по клику, который бот-модуль пометил как бота.
Алерт «Потерянные постбеки»
Сверка с сетью в режиме дозаливки исправляет цифры, но с опозданием на свой интервал, и ничего не говорит о причине. Если сверка раз за разом дозаписывает конверсии, значит постбек этой сети не доходит: ссылка в кабинете сети выключена, указывает на старый домен или отвечает ошибкой.
После каждого прогона сверки, запущенного интеграцией, — по API (Admitad, CityAds, Leads.su)
или по кабинету Unicom24, по расписанию или кнопкой «Сверить сейчас» — трекер считает строки missing, поставленные в очередь приёма. Обновление
отставшего статуса (status_behind) не считается: постбек о такой конверсии приходил. Прогон
«только отчёт» (report, режим по умолчанию) ничего не дозаписывает и алерта не даёт: чтобы
получать алерт, включите у интеграции дозаливку (backfill). Сверка загруженным файлом в подсчёт
не входит.
Событие создаётся, если за прогон дозаписано не меньше 3 конверсий или не меньше 10 % от конверсий, которые сеть отдала за окно сверки. Оба порога меняются в панели: «Алерты» → «Потерянные постбеки», поля «Мин. объём» и «Порог» (0 в «Пороге» отключает проверку доли).
| Куда | Что приходит |
|---|---|
| «Внимание» в панели и приложении | Пункт на интеграцию: сеть, сколько дозаписано за сутки и в последнем прогоне, пример click id, кнопка «Настройка постбека» (карточка подключения, /postbacks?id=…). Виден администраторам. |
| Пуш в приложение | Тем же администраторам. Нажатие открывает «Внимание» на этом пункте, кнопка «Настройка постбека» ведёт в панель. Отключается в приложении: «Ещё» → «Уведомления» → «Потерянные постбеки» (настройка lost_postbacks, по умолчанию включена). Переключатель есть у администратора, если версия трекера знает этот вид; в старой версии приложения пункта нет, пуши приходят. |
| Telegram | В каналы алертов, если бот подключён и вид алерта включён. Кнопка «Открыть в панели» ведёт на карточку подключения постбеков. |
Пуш и сообщение в Telegram уходят не чаще раза в 6 часов на интеграцию («Антиспам-интервал» в настройке алерта). Прогоны внутри этого окна в пункт «Внимания» всё равно попадают, так что счётчик за сутки полный. Пункт можно отметить решённым; он вернётся со следующим уведомлением.
Что проверить, получив алерт: ссылку постбека в кабинете сети (домен, токен подключения, макрос click id) и карантин постбеков — нет ли там тех же конверсий с непривязанным click id.
Исходящие постбеки (отправка конверсий во внешние системы)
По правилам потока конверсия может дополнительно отправляться наружу — очередь в
Postgres с ретраями и экспоненциальным бэкоффом, лог каждой попытки доставки. Адаптеры
реализованы для: Facebook CAPI, TikTok Events API, Google Ads offline conversion import,
GA4 Measurement Protocol, Яндекс.Метрика (офлайн-конверсии), AppMetrica, VK Реклама (офлайн-события) и произвольный
custom_http.
Автоимпорт офферов/статистики партнёрских сетей и история ставок
Отдельно от входящих постбеков (которые сеть шлёт вам на каждую конверсию) есть периодический
почасовой автоимпорт из API самой сети: актуальный
список офферов (название, гео, выплата, статус, капы) и агрегированная статистика конверсий
за период — для сверки с вашими постбеками (детект шейва сети). Настраивается в панели,
раздел «Интеграции» — учётные данные/токен сети шифруются
INOTRACK_INTEG_ENC_KEY (см. обслуживание инстанса); без ключа модуль не падает, просто cost-sync
рекламных площадок и этот автоимпорт не запускаются.
⚠️ Как и пресеты входящих постбеков выше, это отправная точка, а не гарантированно рабочая интеграция «из коробки»: API сетей меняются, поэтому вместо отдельного жёстко прошитого клиента под каждую сеть используется один настраиваемый REST/JSON-клиент — реальные HTTP-запросы с таймаутом и ретраями к адресу, который вы сами указываете в конфиге интеграции по документации сети на момент подключения. Сети под этот клиент: Leadgid, Pampadu, Guruleads, 3snet, PIN-UP Partners, Vavada. Подключение сети с другой формой API (нестандартный ответ, не токен+JSON) — доработка продукта, а не настройка; напишите в поддержку.
История ставок: при каждом импорте трекер сравнивает выплату оффера с сохранённой
ранее — если сеть изменила payout (в т.ч. тихо срезала), это пишется в историю ставок
(таблица payout_history) и сразу уходит алертом в Telegram (тот же канал,
что капы/CR/пропажа постбеков) — не по факту в отчёте через месяц. Уникальность оффера сети —
по паре (рекламодатель, внешний ID оффера), повторный импорт того же оффера обновляет
запись, а не плодит дубли.
Макросы исходящего custom_http
В URL, значениях заголовков и body_template доступны {clickid}, {goal},
{status}, {sum}, {sum_usd}, {sum_rub}, {sum_eur}, {currency}, {txid},
{ext_click_id}, {network}, {conversion_id}, {advertiser_id}, {offer_id},
{source_id}, {sub1}…{sub10}.
{sum} — исходная выплата в валюте сети ({currency}), с сохранением точности.
{sum_usd}, {sum_rub} и {sum_eur} — уже рассчитанные трекером суммы в USD,
RUB и EUR соответственно, округлённые до двух знаков после точки.
Например, если сеть передала 556.8 RUB, а трекер рассчитал 6.187 USD,
шаблон https://example.com/pb?sum={sum_usd}¤cy=USD отправит
https://example.com/pb?sum=6.19¤cy=USD.
Макрос {currency} по-прежнему возвращает валюту сети: для фиксированной валюты
укажите её код в шаблоне явно.
Дальше
Полный список макросов, доступных в ссылках офферов и в постбек-URL — справочник макросов. Публичный API для управления postback-эндпоинтами программно — API.
Словарь значений параметров и сумма по правилу
Входящий маппинг может переводить значения сети в наши названия продуктов и внешние ID офферов, а затем рассчитывать выплату по событию или продукту. Например:
{
"clickid": "subid",
"status": "event",
"status_values": {"approved": "ftd"},
"sum": "payout",
"default_currency": "RUB",
"offer_ext_id": "offer",
"extra": {"product": "product_code", "order_sum": "order_total"},
"value_maps": {
"product": {"card_x": "Кредитная карта"},
"offer_ext_id": {"network_42": "42"}
},
"value_map_defaults": {"product": "Другой продукт"},
"sum_rules": [
{"field": "product", "equals": "Кредитная карта", "amount": 500, "currency": "RUB"},
{"field": "goal", "equals": "ftd", "percent": 30, "percent_of": "order_sum"},
{"field": "", "amount": 100}
],
"sum_rules_override": false
}
Порядок: обычный разбор → ValueMaps → SumRules → resolveZeroSum. Словари работают
только для offer_ext_id и имён из extra: сначала точное совпадение, затем поиск
по приведённому к нижнему регистру значению без пробелов по краям. Если совпадения
нет, используется непустой value_map_defaults для поля; иначе значение сохраняется.
Значение по умолчанию работает и без пар в словаре: в форме можно заполнить только
его, оставив список соответствий пустым. Отсутствующее или пустое входное значение
при этом остаётся пустым. Изменённые исходные значения видны в
extra_raw и offer_ext_id_raw пробного прогона.
Правила проверяются по порядку после словарей. Условие field — status (сырой статус),
goal, offer_ext_id или ключ extra; equals сравнивается без учёта регистра
и крайних пробелов. Пустой field означает «иначе». Нужно ровно одно действие:
положительная amount либо percent (до 1000) от percent_of. База процента
берётся сначала из преобразованного extra, затем из сырого параметра сети.
Нечитаемая база или нулевой результат пропускают правило; результат процента
округляется до шести знаков. Валюта правила нормализуется, включая RUR → RUB;
без неё сохраняется валюта маппинга.
По умолчанию правила заполняют только нулевую сумму. sum_rules_override: true
разрешает заменить и ненулевую выплату сети. Ненулевая сумма явного правила имеет
приоритет над эвристикой карантина unread_sum_param и справочной выплатой оффера.
В пробном прогоне доступны sum_source: "sum_rule", sum_rule_index (с нуля),
sum_rule_detail; в raw конверсии источник записан как _sum_source: "sum_rule".
Без новых настроек поведение прежнее; пустой sum по-прежнему требует allow_no_sum=1.
Ограничения: до 30 словарей, по 100 пар (ключ до 64 символов, значение до 200),
до 30 правил. Новые настройки хранятся в существующем jsonb без миграции.
Одна цель кабинета на клик
Правило принимает goals (список целей, логическое «или») и once_per_click.
Пустой список использует прежнее поле goal; непустой имеет приоритет.
Для заявки настройте goals: ["lead", "reject", "approve"],
once_per_click: true и сопоставьте все три цели с trk_lead в
adapter_config.event_map Метрики. Для VK задайте adapter_config.goal: "trk_lead".
Для одобрения оставьте отдельное правило
goal: "approve" → trk_approve. Используется нормализованная цель сети.
Параллельные события сериализуются по правилу и клику. queued/retrying/sending/sent
резервируют доставку; последующие события пишутся как skipped с причиной
already sent for click («пропущено: уже отправлено по клику»).
После окончательного failed разрешена новая попытка; ручной повтор старого failed
запрещён, если уже есть другая активная или успешная доставка по клику.
В once_per_click правилах Метрики и VK можно задать adapter_config.value
(число или строка с числом, включая 0). Иначе используется выплата, при её отсутствии — 0.
Метрика берёт yclid, VK — rb_clickid; дочерний клик наследует внешний идентификатор
входного клика через parent, если собственного идентификатора нет.
Clickid в составной метке (1xPartners)
Сети семейства 1xPartners (FunPari / fpaff и похожие) могут вернуть всю метку
tag=d_<site>m_<ad>c_<clickid> вместо отдельного clickid. В маппинге укажите
clickid: "tag" и clickid_extract: "c_([0-9A-HJKMNP-TV-Z]{26})$".
В панели это поле «Извлечь clickid (регулярное выражение)»; кнопка
«Подставить шаблон 1xPartners» заполняет выражение.
Например, из tag=d_6270318m_191693c_01ARZ3NDEKTSV4RRFFQ69G5FAV будет извлечён
01ARZ3NDEKTSV4RRFFQ69G5FAV. Пробный разбор показывает уже извлечённое значение.
Выражение должно соответствовать синтаксису RE2 и содержать ровно одну группу
захвата. Пустое выражение отключает извлечение. Если совпадения нет, значение
используется целиком: сеть по-прежнему может прислать чистый clickid.
{
"clickid": "tag",
"clickid_extract": "c_([0-9A-HJKMNP-TV-Z]{26})$",
"status": "status",
"sum": "payout"
}
Гонка pending и окончательного решения
Единица действующего решения — (clickid, txid). Если есть approved или
rejected, выбирается последняя по (version, conversion_id) строка среди
окончательных решений. Pending (lead, reg, hold) не перекрывает её,
даже если принят позже. Без окончательных действует последняя pending.
Перерешение approve → reject → approve сохраняет последний approve.
Пустой txid означает независимую конверсию.
Окончательное решение сети («одобрено» или «отклонено») приоритетнее статуса «в ожидании»: запоздалый pending не перекрывает его. Этот порядок одинаков для отчётов, прогноза выплат, финансов, правил, бандита и дневных сводок. Окончательные решения учитываются также до начала периода отчёта.
Запоздалый pending по той же сети, клику и транзакции записывается в ClickHouse
и историю статусов и отмечается в логе как обратный переход. Исходящие правила
для него подавляются уже при наличии окончательного решения; резервирование
once_per_click не меняется. Обычные повторные pending по прежнему ключу
подавляются входящим дедупом.
Режим цены исходящего правила
POST/PUT/GET /api/internal/postback/rules используют price_mode:
payout (по умолчанию), zero, forecast. Неизвестный режим — HTTP 400.
PUT без поля возвращает режим payout.
payout: исходная выплата; сохраняется фиксированныйadapter_config.valueдля once_per_click Метрики/VK.zero: денежные поля исходящей копии обнуляются. Метрика получает CSV без Price/Currency; VK —e=RG%3A/<goal>без суммы.forecast: выплата × вероятность апрува оффера. Для цели событияapproveпередаётся полная выплата. Фиксированныйadapter_config.valueне применяется.
Апрув — текущие approved/(approved+rejected) за последние 30 дней, без тестовых
и исключённых конверсий, с той же дедупликацией решений, что в прогнозе отчёта.
Воркер загружает общий кэш при старте и обновляет раз в 12 минут; отправка не
обращается к ClickHouse. Нет истории — справочная вероятность
offers.forecast_default_rate (nullable, доля 0..1, задаётся администратором БД),
затем 0.5. Текстовые описания апрува сетей автоматически не разбираются.
При отказе ClickHouse история заменяется справочником/дефолтом и пишется warning;
доставка продолжается. Явный ручной тест правила обновляет прогноз отдельно.
Расчёт меняет только исходящую копию, не финансовую выплату.
В response журнала попытки записываются price_mode, price, price_rub,
исходные payout, payout_rub и множитель rate; исходный payload сохраняет выплату.
Для payout rate равен 1; фиксированная ценность, если задана, видна в price.
Креды в эти поля не добавляются.
Формат VK без суммы подтверждён документацией Top.Mail.Ru. Отсутствие суммы может включать ценность цели по умолчанию, заданную в кабинете Top.Mail.Ru.
Тестовый флаг входящего постбека
В param_mapping можно указать test_param — имя параметра сети, например
{"test_param":"aptest","test_values":["1","true","yes"]}. Если test_values
отсутствует или пуст, используются 1, true, yes. Значения сравниваются точно,
с учётом регистра, без удаления пробелов. Пользовательский список заменяет стандартный.
Пустой test_param отключает распознавание; отсутствующий параметр означает обычную
конверсию. API отклоняет имя с любыми пробельными символами (включая Unicode),
пустые значения и список без test_param.
PUT /api/internal/postback/endpoints/{id}/mapping принимает сам объект маппинга
в теле запроса, без обёртки param_mapping. Для безопасного разбора
POST /api/internal/postback/test передайте этот объект в поле mapping.
Эти контракты также описаны в OpenAPI под /api/v1/postback/.
При aptest=1 конверсия сохраняется с is_test=1 в ClickHouse и остаётся в истории.
Финансовые запросы и отчёты исключают тестовые строки. Событие конверсии не публикуется
в общую шину, поэтому начисления и исходящие постбеки не запускаются.
POST /api/internal/postback/test возвращает is_test на верхнем уровне и в parsed;
в would_write признак называется IsTest, как остальные поля события.
Для тестовой конверсии would_fire_rules пуст. Проверка сама ничего не записывает.