API: трекинг и постбэк
Трекинговые эндпоинты MeerPartners: редирект /r/{code}, пиксель /p/{code}.gif и приём конверсий POST /api/v1/postback с HMAC-подписью.
Трекинг — это «горячий путь» атрибуции: переход по ссылке фиксирует клик и ставит cookie, а конверсия приходит обратно через S2S-постбэк. Редирект и пиксель живут вне версии (/r/..., /p/...) ради скорости; постбэк — под /api/v1. Пошаговые гайды: Трекинг-ссылки и Постбэк.
GET /r/{code}
/r/{code}🔒 —Редирект по трекинг-ссылке. Резолвит оффер, фиксирует клик (асинхронно, не блокируя ответ), ставит подписанную cookie атрибуции aff_attr и отдаёт 302 на лендинг. Это «always-302»: даже при сбое записи клик уходит в fallback-лог, а редирект всё равно происходит.
Path: code — короткий код ссылки (из POST /affiliate/links).
Query-параметры (опционально):
sub_id1stringoptionalsub1.sub_id2stringoptionalsub2.sub_id3stringoptionalsub3.sub_id4stringoptionalsub4.sub_id5stringoptionalsub5.Ответ: 302 Found. Заголовок Location ведёт на лендинг оффера с добавленным aff_click=<click_uid> (server-side fallback атрибуции для Telegram/WebView, где cookie часто теряется). Ставится cookie aff_attr (HMAC-подпись, Max-Age = окно атрибуции оффера, SameSite=Lax). Для ботов cookie не ставится.
HTTP/1.1 302 Found
Location: https://acme.com/landing?utm=promo&aff_click=8f1c0a2e-...
Set-Cookie: aff_attr=eyJ...; Max-Age=2592000; Path=/; SameSite=LaxОшибки: TRACKING_LINK_NOT_FOUND (404 — неизвестный код), LINK_INACTIVE (410 — ссылка отключена, нет fallback), OFFER_INACTIVE (410 — оффер неактивен, нет fallback), OFFER_NO_LANDING (503 — у активного оффера не задан landing), TRACKING_RATE_LIMITED (429). При наличии fallback_url неактивная ссылка/оффер редиректят на него вместо 410.
GET /p/{code}.gif
/p/{code}.gif🔒 —Пиксель-фоллбэк: то же фиксирование клика и cookie, но вместо редиректа отдаётся прозрачный 1×1 GIF. Удобно вставлять в <img> там, где нельзя редиректить (письма, виджеты).
Path/Query — как у /r/{code} (sub_id1..5).
Ответ: 200 OK, Content-Type: image/gif, заголовок Cache-Control: no-store, no-cache, must-revalidate, private, тело — 43 байта GIF. Cookie aff_attr ставится так же (кроме ботов).
POST /api/v1/postback
/api/v1/postback🔒 HMACПриём конверсии S2S от бизнеса. Подписывается ключом tenant_api_key со скоупом postback. HMAC считается по сырому телу запроса — не пересобирайте JSON после подписи.
Заголовки
X-Api-Key-Idstringrequiredkey_id).X-TimestampstringrequiredPOSTBACK_STALE_TIMESTAMP.X-Signaturestringrequiredhex(HMAC_SHA256(secret, signing_string)).X-Tenant-Idstringoptionalsigning_string = "{method}\n{path}\n{X-Timestamp}\n{sha256_hex(raw_body)}". Полный разбор и примеры подписи на разных языках — на странице Постбэк.
Тело
external_order_idstringrequiredevent_typestringrequiredsale, lead, registration, refund, chargeback.refstringoptionalclick_id (он же click_uid) или код ссылки. До 128 символов.sub_idstringoptionalamountstringoptionalsale (вместе с currency).currencystringoptionalsale.statusstringoptionalapproved или pending.occurred_atstringoptionalmetaobjectoptional{
"external_order_id": "ORD-100500",
"event_type": "sale",
"ref": "8f1c0a2e-7b3d-4c1a-9f2e-1a2b3c4d5e6f",
"amount": "2990.00",
"currency": "RUB",
"status": "approved",
"occurred_at": "2026-06-14T12:30:00Z"
}Ответ
acceptedbooleanrequiredduplicatebooleanrequiredtrue, если повтор по external_order_id (идемпотентный реплей).conversion_idintegeroptionalcommissionobjectoptionalreasonstringoptionalaccepted:false (например POSTBACK_UNKNOWN_REF, POSTBACK_REFUND_NO_CONVERSION).{
"accepted": true,
"duplicate": false,
"conversion_id": 778,
"commission": {
"id": 9100,
"amount": "750.00",
"currency": "RUB",
"status": "pending",
"hold_until": "2026-06-28T12:30:00Z"
}
}{ "accepted": true, "duplicate": true, "conversion_id": 778 }2xx и при accepted:false
Логически обработанные события (включая «не нашли клик по ref» и повтор) возвращают 200 с флагами accepted/duplicate/reason. HTTP-ошибки (4xx/5xx) — только для проблем аутентификации, подписи, лимита или валидации. Подробнее об идемпотентности и дедупе — на странице Лимиты и идемпотентность.
Ошибки: TENANT_API_KEY_INVALID (401), TENANT_API_KEY_SCOPE_DENIED (403 — нет скоупа postback), POSTBACK_BAD_SIGNATURE (401), POSTBACK_STALE_TIMESTAMP (400), POSTBACK_REPLAY (409 — повтор подписи), POSTBACK_TENANT_MISMATCH (403), POSTBACK_MISSING_FIELD (422 — нет обязательного поля), POSTBACK_RATE_LIMITED (429), TENANT_SUSPENDED (403).