Контракт из двух шагов
- Принять
click_idв адресе посадочной страницы и сохранить его рядом с заказом — так, чтобы он пережил закрытие вкладки. - В момент целевого действия отправить серверный запрос с этим
click_id, номером заказа и статусом.
Адрес один на всю платформу:
https://api.recca.ru/cpa/postback/<offer_id>.
Идентификатор оффера, секрет и токен GET-ссылки выдаёт кабинет — они
разные у разных офферов.
Две двери
| POST с подписью | GET-ссылка | |
|---|---|---|
| Кому подходит | Есть разработчик | В CRM есть только поле «URL постбэка» |
| Параметры | Тело JSON | Строка запроса |
| Право доступа | HMAC-подпись в заголовке X-CPA-Signature | Токен secure в адресе |
| Статус | Рекомендуемый | Запасной: токен виден в журналах промежуточных серверов |
POST с подписью
POST https://api.recca.ru/cpa/postback/<offer_id>
Content-Type: application/json
X-CPA-Signature: <hex(HMAC-SHA256(secret, canonical))>
{
"click_id": "clk_a1b2c3",
"external_id": "order-10421",
"status": "confirmed",
"sum_rub": 5000,
"goal": "sale"
} Параметры
| Поле | Обязательно | Что означает |
|---|---|---|
click_id | да | Идентификатор перехода — приходит в адресе вашей посадочной страницы. Без него запрос отклоняется (400). |
external_id | да | Ваш номер заказа. Ключ идемпотентности: повтор не создаёт вторую конверсию. До 200 символов, не может начинаться с «recca:». |
status | да | Статус заказа у вас — см. таблицу ниже. |
sum_rub | для процентных моделей | Сумма заказа в рублях, число. |
sub_id | нет | Сквозная метка партнёра, если получали её в ссылке. До 200 символов. |
goal | нет | Код цели воронки: латиница, цифры, «_», «.», «-», до 64 символов. Не передан — основная ставка оффера. |
Подпись
HMAC-SHA256 в шестнадцатеричном виде, ключ — секрет оффера, подписывается
строка из полей через двоеточие. Подпись едет в заголовке, а не в теле:
поле signature в теле игнорируется.
click_id:external_id:status:sum_rub:sub_id[:goal[:timestamp]] - Пустые значения остаются пустыми сегментами: нет суммы и метки — строка заканчивается двоеточиями, разделители не схлопываются.
- Шестой сегмент
goalдобавляется, если поле передано в запросе (даже «1»). - Заголовок
X-CPA-Timestamp(секунды Unix) необязателен; если он есть, подписывается седьмым сегментом (пустая цель — пустой шестой), а запрос старше пяти минут отклоняется.
Секрет можно заменить без остановки интеграции: прежний принимается ещё 7 суток. Подпись, а не список адресов: адрес меняется при каждом переезде инфраструктуры, а секрет переживает переезд.
Статусы
| Значение | Как поймёт сеть |
|---|---|
pending, wait, waiting, on_hold | Ожидание: конверсия записана, вознаграждение не начисляется. |
cancel, reject | Отмена: гасит конверсию. Только эти два слова и только строчными. |
любое другое слово | Подтверждение: начинается холд. Это относится и к «declined», и к «3» — в POST они НЕ отменяют конверсию. |
GET-ссылка для CRM
GET https://api.recca.ru/cpa/postback/<offer_id>?clickid=clk_a1b2c3&action_id=order-10421&sum=5000&status=1&secure=<токен>
Подписи у GET нет: право доказывает токен secure из кабинета
(выводится из секрета оффера, сам секрет в адрес не попадает). Имена
параметров — как у Affise: clickid, action_id,
sum, status; цели — параметром goal.
Здесь статус понимает и числа: 1, 5,
approved — подтверждение; 2,
pending — ожидание; 3, cancel,
declined — отмена. Пустой статус — подтверждение. Обе двери
ведут в один приёмник и дают одинаковый результат.
Цели воронки
Внутри одного оффера может быть несколько шагов — регистрация,
промежуточная веха, оплата. Каждый приходит своим постбэком с параметром
goal; дедупликация считается по тройке «сеть — заказ — цель»,
поэтому оплата не перетирает регистрацию, а порядок прихода не важен.
Веха — цель за ноль. Она не создаёт вознаграждения и не расходует лимит, но показывает доходимость: где именно ломается воронка, видно до того, как рекламодатель начнёт массово отклонять конверсии.
Коды ответа
| Код | Что произошло |
|---|---|
201 | Конверсия создана. |
200 | Заказ уже был засчитан (в теле «idempotent: true»). Повтор безопасен и вознаграждение второй раз не начисляет. |
400 | Не хватает обязательного поля или оно не разобралось. |
403 | Подпись или токен не подошли, метка времени вышла из окна в пять минут, неизвестный ключ подписи. |
409 | Конфликт: тот же заказ с другой суммой, номер заказа занят чужим оффером сети, окно атрибуции истекло, недопустимый переход статуса. |
429 | Превышен лимит; повторите после паузы из заголовка Retry-After. |
500 | Ошибка на нашей стороне; повторите запрос — он идемпотентен. |
В теле ошибки — машинный код и пояснение. Если click_id
пришёл в верном формате, но такого перехода нет, конверсия не теряется:
она записывается как «переход не найден» и поднимется, когда придёт
постбэк с верным идентификатором.
Лимиты
2 000 подписанных запросов в минуту на оффер по умолчанию (оператор сети может задать от 60 до 20 000). С одного адреса ограничиваются только отказы по праву — 30 в минуту; верно подписанные запросы это ограничение не расходуют.
Проверка до запуска трафика
В кабинете есть тестер: он отправляет настоящий постбэк через настоящий приёмник с настоящей подписью, то есть проверяет ровно тот путь, по которому пойдут боевые запросы. Строки, созданные тестером, помечаются тестовыми и не попадают ни в статистику, ни в рейтинг оффера.
Запускать трафик до успешной проверки не стоит: первые переходы уйдут в никуда, а восстанавливать доверие партнёров дороже, чем потратить час на тест.
Если конверсия не засчиталась
Журнал попыток в кабинете хранит запросы за 90 суток с методом, параметрами и кодом ответа. Строки нет только у запросов, отклонённых до того, как стало известно, чей это оффер: нераспознанный адрес и тело, не прошедшее разбор.
Полная инструкция с примерами под конкретные CRM — в справке кабинета, статья «Настройка S2S-постбека». Обзор того, как это устроено со стороны сети, — приём конверсий по S2S; что происходит с конверсией дальше — холд и подтверждение.