API: Affiliate (self-service)
Self-service API инфлюенсера MeerPartners: профиль и KYC, каталог офферов, трекинг-ссылки, баланс, статистика и методы вывода.
Группа /api/v1/affiliate/* — кабинет инфлюенсера через API. Все эндпоинты требуют JWT инфлюенсера (Authorization: Bearer <access_token>). affiliate_id всегда берётся из токена, никогда из запроса (анти-IDOR). Денежные суммы — строки NUMERIC.
Embed-токен (scoped)
Scoped embed-токен (scope: affiliate:embed, выдаётся через token-exchange) работает в этой группе только на чтение в рамках своего affiliate_id. Мутации — создание/удаление методов вывода, изменение профиля и отправка KYC — требуют полного токена; иначе 403 EMBED_SCOPE_DENIED.
Списочные ответы здесь имеют форму { "items": [...], "total": N }.
Профиль
GET /affiliate/profile
/api/v1/affiliate/profile🔒 Bearer JWTПрофиль инфлюенсера: контакты, язык, статус KYC, реферальный код.
user_idintegerrequiredaffiliate_idintegerrequiredemailstringoptionaldisplay_namestringoptionallanguage_codestringoptionalru / en).statusstringoptionalkyc_statusstringoptionalnone / pending / verified / rejected.payout_currencystringoptionalreferral_codestringoptionalcreated_atstringoptional{
"user_id": 1042,
"affiliate_id": 88,
"email": "creator@example.com",
"display_name": "Аня",
"language_code": "ru",
"status": "active",
"kyc_status": "verified",
"payout_currency": "RUB",
"referral_code": "ANYA7K",
"created_at": "2026-05-01T10:00:00Z"
}PUT /affiliate/profile
/api/v1/affiliate/profile🔒 Bearer JWTОбновить отображаемое имя и/или язык. Требует полный токен.
display_namestringoptionallanguage_codestringoptionalru или en.Возвращает обновлённый объект профиля (как в GET /affiliate/profile).
POST /affiliate/profile/kyc
/api/v1/affiliate/profile/kyc🔒 Bearer JWTОтправить документы на KYC-проверку. Переводит статус из none/rejected в pending. Требует полный токен.
document_typestringrequiredpassport, national_id, driver_license), 1–64 символа.document_refstringoptional{ "kyc_status": "pending" }Ошибки: KYC_ALREADY_SUBMITTED (409 — уже pending/verified), PROFILE_NOT_FOUND (404), EMBED_SCOPE_DENIED (403).
Офферы
GET /affiliate/offers
/api/v1/affiliate/offers🔒 Bearer JWTКаталог доступных офферов: все публичные плюс приватные, к которым выдан доступ.
Query-параметры: tenant_id (фильтр по бизнесу), geo (2-буквенный код страны), model (cpl/cpa/revshare/hybrid), skip (0+), limit (1–200, по умолчанию 50).
{
"items": [
{
"id": 501,
"tenant_id": 17,
"name": "Acme Premium",
"slug": "acme-premium",
"visibility": "public",
"status": "active",
"monetization_model": "cpa",
"currency": "RUB",
"hold_days": 14,
"geo": ["RU", "KZ"],
"cpa_amount": "750.00",
"cpl_amount": null,
"revshare_percent": null,
"multilevel_enabled": true,
"affiliate_access_status": null
}
],
"total": 12
}affiliate_access_status — доступ к приватному офферу (approved / requested / null для публичных).
GET /affiliate/offers/{offer_id}
/api/v1/affiliate/offers/{offer_id}🔒 Bearer JWTДетальная карточка оффера: всё из списка плюс условия и параметры multi-level.
termsobjectoptionalattribution_window_hoursintegeroptionalmax_levelsintegeroptionallevel_ratesobjectoptionalЕсли status = paused — это отражается в поле, а UI показывает причину (OFFER_PAUSED).
Трекинг-ссылки
GET /affiliate/links
/api/v1/affiliate/links🔒 Bearer JWTСписок ваших трекинг-ссылок. Query: skip (0+), limit (1–500, по умолчанию 100).
POST /affiliate/links
/api/v1/affiliate/links🔒 Bearer JWTСоздать ссылку на оффер. Возвращает короткий code для пути /r/{code}.
offer_idintegerrequiredsub_id1stringoptionalsub_id2stringoptionalsub_id3stringoptional{
"id": 9001,
"offer_id": 501,
"tenant_id": 17,
"code": "a1B2c3",
"is_active": true,
"deep_link_params": {},
"created_at": "2026-06-14T12:00:00Z"
}Ошибки: LINK_LIMIT_REACHED (422), OFFER_PAUSED (422), OFFER_NOT_FOUND (404).
GET /affiliate/links/{link_id}
/api/v1/affiliate/links/{link_id}🔒 Bearer JWTСсылка вместе со статистикой.
clicksintegeroptionalunique_clicksintegeroptionalconversionsintegeroptionalepcstringoptional{
"id": 9001,
"offer_id": 501,
"tenant_id": 17,
"code": "a1B2c3",
"is_active": true,
"deep_link_params": {},
"created_at": "2026-06-14T12:00:00Z",
"clicks": 4210,
"unique_clicks": 3880,
"conversions": 96,
"epc": "17.05"
}Как формировать ссылку с метками и макросами — на странице Трекинг-ссылки.
Баланс
GET /affiliate/balance
/api/v1/affiliate/balance🔒 Bearer JWTБаланс по валютам: доступно к выводу, в hold и заблокировано под активную заявку. Валюты с нулевыми суммами в ответ не попадают.
balancesarrayrequiredbalances[].currencystringrequiredbalances[].payablestringrequiredbalances[].holdstringrequiredbalances[].lockedstringrequired{
"balances": [
{ "currency": "RUB", "payable": "12400.00", "hold": "3100.00", "locked": "0.00" },
{ "currency": "USD", "payable": "85.00", "hold": "0.00", "locked": "10.00" }
]
}Статистика
GET /affiliate/stats
/api/v1/affiliate/stats🔒 Bearer JWTАгрегаты по кликам, конверсиям и комиссиям: по дням, по офферам и по уровням сети. Query: date_from, date_to (формат YYYY-MM-DD).
period_fromstringoptionalperiod_tostringoptionaltotal_clicksintegerrequiredtotal_conversionsintegerrequiredtotal_commissionstringrequiredby_dayarrayrequiredby_offerarrayrequiredby_levelarrayrequired{
"period_from": "2026-06-01",
"period_to": "2026-06-14",
"total_clicks": 18240,
"total_conversions": 412,
"total_commission": "215300.00",
"by_day": [
{
"day": "2026-06-14",
"offer_id": 501,
"offer_name": "Acme Premium",
"tenant_id": 17,
"clicks": 1320,
"unique_clicks": 1190,
"conversions": 31,
"revenue": "0.00",
"commission_total": "23250.00",
"currency": "RUB"
}
],
"by_level": [
{ "level": 0, "currency": "RUB", "commission_total": "190000.00", "conversions": 380 },
{ "level": 1, "currency": "RUB", "commission_total": "25300.00", "conversions": 32 }
]
}Методы вывода
GET /affiliate/payout-methods
/api/v1/affiliate/payout-methods🔒 Bearer JWTСписок сохранённых методов вывода. Реквизиты зашифрованы и наружу не отдаются — только маскированный хвост display_last4.
{
"items": [
{
"id": 301,
"method_type": "card",
"display_last4": "4242",
"is_default": true,
"is_verified": true,
"created_at": "2026-05-10T09:00:00Z"
}
]
}POST /affiliate/payout-methods
/api/v1/affiliate/payout-methods🔒 Bearer JWTДобавить метод вывода. Реквизиты шифруются AES-256-GCM перед записью. Требует полный токен (embed → 403 EMBED_SCOPE_DENIED).
method_typestringrequiredcard, crypto, и т.п.), 1–24 символа.detailsobjectrequiredcard_number, wallet_address). Шифруются на сервере.is_defaultbooleanoptionalfalse.В ответе (201) — объект метода с display_last4; полные реквизиты не возвращаются.
DELETE /affiliate/payout-methods/{method_id}
/api/v1/affiliate/payout-methods/{method_id}🔒 Bearer JWTУдалить свой метод вывода. Требует полный токен. Успех — 204 No Content без тела.