CashoutGuard

Документация

Один скрипт в браузере, один вызов API с вашего сервера. Всё, что нужно для запуска, на одной странице.

Быстрый старт

Вам понадобятся публичный ключ (pk_...) для браузера и секретный ключ (sk_...) для сервера. Оба находятся в панели, в разделе «Сайты и ключи».

1. Добавьте скрипт

Разместите этот тег на страницах, где пользователи регистрируются, входят, кликают по офферам или запрашивают вывод. Скрипт инициализируется сам, используя data-key

<script src="https://cashoutguard.com/v1/agent.js" data-key="pk_live_YOUR_PUBLIC_KEY" async></script>

2. Соберите request_id и отправьте его на сервер

Вызовите collect() в нужный момент, передав название события. Результат: { request_id, visitor_id }

const { request_id } = await CashoutGuard.collect({ event: 'cashout' });

collect() никогда не завершается reject. При сбое (блокировка, офлайн, таймаут) он возвращает request_id: null и строку с ошибкой. Всё равно отправляйте форму, а решение пусть принимает сервер.

3. Запросите решение с сервера

Отправьте событие POST-запросом на /v1/evaluate с секретным ключом в заголовке Authorization: Bearer sk_live_...

Никогда не размещайте секретный ключ в коде браузера или мобильного приложения. Вызывать /v1/evaluate должен только ваш сервер.

Запрос evaluate

POST https://cashoutguard.com/v1/evaluate оценивает одно событие для одного аккаунта, связывает его с устройством, сетью и адресом выплаты и возвращает решение. Отправляйте JSON.

ПолеТипОбязательноОписание
eventstringОбязательноsignup, login, offer_click, conversion, cashout или custom.
account_idstringОбязательноID пользователя у вас, до 191 символа. Используйте непрозрачный ID, а не email.
request_idstringНеобязательноИз collect() в браузере. Действует 1 час. Без него у нас есть только данные о сети.
ipstringНеобязательноIP пользователя. Нужен, только если у вас нет request_id, например для postback.
emailstringНеобязательноХранится в виде хеша. Выявляет одноразовые домены и email, общие для нескольких аккаунтов.
payout_addressstringНеобязательноEmail PayPal, кошелёк или счёт, куда уходят деньги. Хранится в виде хеша.
payout_methodstringНеобязательноПроизвольный текст, например paypal, usdt или giftcard.
amountnumberНеобязательноСумма вывода или конверсии.
currencystringНеобязательноКод валюты, например USD. Для выводов по умолчанию USD.
offer_idstringНеобязательноID оффера для offer_click и conversion. Используется для расчёта скорости выполнения.
offer_countrystringНеобязательноСтрана, за которую платит оффер (код ISO, например US), в конверсиях. Пользователь в другой стране помечается.
geo_countrystringНеобязательноВаша собственная геолокация IP пользователя (код ISO). Если она расходится с нашей, IP, скорее всего, выход прокси.
transaction_idstringНеобязательноID транзакции конверсии в сети. Используется для поиска дублей.
offer_namestringНеобязательноНазвание оффера так, как его видят пользователи. Показывается в панели вместо сырого id.
click_idstringНеобязательноВаш id клика. Передавайте одно и то же значение в offer_click и в конверсии, чтобы связать их.
sourcestringНеобязательноИсточник события, например название оффервола или сети.
metaobjectНеобязательноДо 20 дополнительных текстовых полей, сохраняемых с событием (например, sub id).

Ответ

Ответ всегда имеет одинаковую структуру. Неприменимые поля равны null.

  • score принимает значение от 0 до 100. Причины комбинируются так, что несколько средних сигналов складываются, не превышая 100.
  • reasons перечисляет все сработавшие сигналы, начиная с самого сильного, с их весом, подробностями и понятной английской подписью, которую можно показать как есть.
  • device.confidence показывает, насколько уникально выглядит устройство. Отпечатки можно подделать, поэтому мы никогда не заявляем стопроцентную уверенность.
  • linked_accounts перечисляет другие аккаунты с тем же устройством, адресом выплаты или email.
  • cashout заполняется только для событий cashout и показывает статус в вашей очереди проверки.

Решения и action

Ориентируйтесь на поле action, а не на decision. Пороги ниже заданы по умолчанию, их можно изменить для каждого сайта в панели.

РешениеОценка (по умолчанию)action в shadowaction в enforceЧто делать
allow0-49allowallowПродолжайте как обычно.
review50-79allowreviewЗадержите вывод или запросите дополнительную проверку. Событие появится в вашей очереди проверки.
block80-100allowblockОстановите действие. Заморозьте баланс или откажите в регистрации.

В теневом режиме action всегда равно allow, поэтому тот же код можно безопасно выкатить до включения enforce. При переключении на enforce в вашем коде ничего не меняется.

Типы событий

Отправляйте те события, которые у вас есть. Важнее всего signup и cashout; conversion нужны для проверки скорости выполнения офферов.

СобытиеКогда отправлятьЧто ловит
signupАккаунт созданМультиаккаунты, боты, регистрации через VPN, одноразовые email
loginУспешный входСовместное использование аккаунта, смена страны, новые устройства
offer_clickПользователь открывает офферЗапускает отсчёт для проверки скорости выполнения
conversionPostback от offerwall или сетиСлишком быстро выполненные офферы, дубли транзакций, всплески конверсий
cashoutПользователь запрашивает выводОбщие адреса выплат, частые выводы, выводы с новых аккаунтов
customВсё остальное, что вы хотите оценитьСигналы устройства и сети

Офферволы и постбэки

Конверсии офферволов приходят постбэком, сервер к серверу, без браузера. CashoutGuard связывает каждую конверсию с кликом, с которого она началась, и оценивает её по устройству и сети этого клика.

1. Когда пользователь открывает оффер

Соберите данные в браузере и отправьте offer_click с оффером и вашим id клика.

2. Когда приходит постбэк

Отправьте conversion из обработчика постбэков с тем же account_id и click_id. request_id не нужен. Передайте IP пользователя, если оффервол его сообщает.

Конверсии проверяются на: слишком быстрое выполнение для оффера, конверсию без клика, клик и конверсию из разных стран, заработок намного выше обычного дня аккаунта и повторные id транзакций.

Сети офферволов

Если у вас сеть с множеством издателей, передавайте id аккаунтов с издателем и включите «Режим сети офферволов» в разделе «Сайты». Тогда аккаунты связываются только внутри одного издателя, ведь один человек нередко пользуется сайтами нескольких ваших издателей. Формат: publisher_id:user_id

Каталог офферов

POST /v1/offers отправляет названия ваших офферов (до 1 000 за вызов). Прошлые и будущие события будут показывать настоящее название, даже если в них только id.

Коды причин

Эти коды приходят в reasons[].code. Текст показывайте модераторам, а в логике используйте код.

КодЗначениеГруппаВес
ip_torВыходной узел TorСеть60
ip_vpnVPN-подключениеСеть45
ip_datacenterIP дата-центра / хостингаСеть40
timezone_mismatchЧасовой пояс браузера не совпадает с местоположением IPСеть20
webrtc_ip_leakУтечка реального IP из другой страныСеть30
ip_multi_timezoneОдин IP с разными часовыми поясами (выход прокси)Сеть50
proxy_farm_ipНесколько аккаунтов на одном IP с одинаковым иностранным временем (общий прокси)Сеть60
provider_rotationМного интернет-провайдеров за несколько дней при иностранном времени (ротируемый резидентный прокси)Сеть45
privacy_relayiCloud Private Relay (функция приватности)Сеть5
proxy_headersЗапрос пришёл через проксиСеть20
geo_sources_disagreeИсточники геолокации расходятсяСеть45
ip_shared_with_accountsТот же IP сегодня использовали другие аккаунтыСеть25
country_changedСменилась странаСеть15
impossible_travelНевозможное перемещение: IP двух далёких стран в течение нескольких часовСеть50
locale_country_mismatchЯзык браузера другой страныСеть30
phone_country_mismatchТелефон из другой страны, чем IPСеть20
ip_flagged_on_networkIP заблокирован на других сайтахСеть25
device_shared_with_accountsУстройство используется другими аккаунтамиУстройство55
automation_detectedБот или средство автоматизацииУстройство70
auto_clickerАвтокликер на телефонеУстройство55
scripted_behaviorСтраницей управлял скриптУстройство45
emulator_or_vmЭмулятор или виртуальная машинаУстройство45
browser_tamperingПодмена / спуфинг браузераУстройство35
device_rootedТелефон с root-доступомУстройство25
incognitoРежим инкогнитоУстройство10
device_spoofedПоддельная модель телефонаУстройство55
emulator_profileПрофиль эмулятора по умолчаниюУстройство60
cloud_phoneОблачный телефонУстройство60
phone_farm_displayЭкран фермы телефоновУстройство45
device_market_mismatchТелефон только для Китая за рубежомУстройство25
storage_cleared_reappearedОчистил cookies и вернулсяУстройство15
no_device_dataДанные устройства не переданыУстройство15
request_reusedТокен устройства повторно использован другим аккаунтомУстройство40
device_farm_proxyФерма телефонов на резидентных проксиУстройство85
device_clonesКлоны устройства: один телефон сбрасывает свою личность, чтобы выдавать себя за много новых аккаунтов в одной сетиУстройство55
payout_address_sharedАдрес выплаты используют другие аккаунтыАккаунт70
email_disposableОдноразовый emailАккаунт25
email_invalidАдрес, на который не может прийти почта (такого почтового домена нет)Аккаунт35
email_sharedТот же email, что у другого аккаунтаАккаунт50
phone_sharedТелефон общий с другими аккаунтамиАккаунт50
phone_voipVoIP или виртуальный номерАккаунт40
phone_invalidНедействительный номерАккаунт30
many_devices_per_accountСлишком много устройств на одном аккаунтеАккаунт20
flagged_on_networkОтмечен на других сайтах под защитой CashoutGuardАккаунт45
face_same_personТо же лицо, что у других аккаунтовАккаунт0
offer_completed_too_fastОффер выполнен нереально быстроПоведение40
slow_after_clickКонверсия спустя долгое время после кликаПоведение0
conversion_velocityСлишком много конверсий в часПоведение30
conversion_without_clickКонверсия без клика с вашего offerwallПоведение35
click_conversion_country_mismatchКлик из одной страны, конверсия из другойПоведение30
offer_country_mismatchСтрана оффера не совпадает со страной пользователяПоведение45
click_velocityСлишком много кликов по офферам за несколько минутПоведение35
earnings_spikeДоход намного выше обычного пользователяПоведение30
source_high_reversalsИсточник с большим числом возвратовПоведение45
offer_high_reversalsОффер с большим числом возвратовПоведение35
duplicate_transactionДублирующийся ID транзакцииПоведение60
offer_repeated_other_publisherТот же оффер уже выполнен через другого паблишераПоведение85
offer_repeated_other_accountТот же оффер уже выполнен другим аккаунтом на этом устройствеПоведение85
offer_farm_burstВолна фермы: много новых аккаунтов с фермерскими устройствами на этом оффере за несколько часовПоведение30
signup_burstВсплеск регистраций: несколько аккаунтов зарегистрировались за секунды с разных IPПоведение25
face_check_requiredНужна проверка лица, ещё не пройденаПоведение0
face_check_failedПроверка лица не пройденаПоведение0
publisher_farm_waveВолна фермы его паблишера: большинство новых аккаунтов, которых он прислал на этот оффер, были с облачных телефонов или эмуляторовПоведение55
cashout_velocityСлишком много выводов в деньПоведение30
new_account_cashoutВывод с совсем нового аккаунтаПоведение20
blocklistedВ вашем чёрном спискеВаши списки100

Веса объединяются по принципу noisy-OR: score = 100 x (1 - произведение (1 - weight/100)). Два сигнала по 40 дают 64, а не 80. Совпадение с чёрным списком всегда даёт 100.

Webhooks

Укажите URL вебхука в панели. Мы отправляем POST на каждое событие с оценкой block (event.blocked), когда аккаунт переходит в block (account.blocked) и когда команда принимает решение по выводу (cashout.decided). Игнорируйте ненужные типы.

Каждый запрос подписывается вашим секретом webhook. HMAC-SHA256 от исходного тела в hex передаётся в заголовке X-CashoutGuard-Signature

Ответьте любым статусом 2xx. Неудачные доставки повторяются до 5 раз: через 10 секунд, 1 минуту, 5 минут и 15 минут.

Статус аккаунта

GET /v1/accounts/{account_id} возвращает текущую картину риска по аккаунту, не создавая событие.

POST /v1/accounts/{account_id}/status позволяет вашим собственным инструментам модерации менять статус аккаунта.

  • active: Обычная оценка.
  • allowlisted: Оценка ограничена ниже порога проверки. Для доверенных пользователей и сотрудников.
  • blocked: Любое событие возвращает block с оценкой 100.

Отмены и точность

POST /v1/outcomes сообщает, что стало с конверсиями после нашей оценки: отменены офферволлом или рекламодателем (chargeback) или подтверждены. Мы сопоставляем ваши id и измеряем движок на вашем трафике на странице «Точность».

Без кода: загрузите на странице «Точность» ежемесячный файл отмен от офферволлов (CSV или Excel). Колонку с id найдём сами.

PHP, Node.js, Python, Android

SDK не нужен. Достаточно обычного HTTP-запроса с коротким таймаутом. Полный пример для вывода:

Ошибки и лимиты

HTTPТелоЗначение
401missing_or_invalid_secret_keyСекретный ключ отсутствует, неверен или отозван. В ответе указана причина в "reason" (missing, public_key, unknown_secret, placeholder, malformed) и способ исправить в "hint".
404not_foundАккаунт не найден (эндпоинты аккаунтов).
422{ "message", "errors" }Некорректное тело запроса. В errors перечислены все поля.
429Too Many RequestsДостигнут лимит запросов. Серверный API допускает 3 000 запросов в минуту на сайт.
401 · agent.jsunknown_public_keydata-key не является публичным ключом ни одного сайта. Скопируйте pk_live_... заново в разделе «Установка».
403 · agent.jsorigin_not_allowedДомена страницы нет в разрешённых источниках сайта. Добавьте его в разделе «Сайты» или оставьте список пустым. localhost работает всегда. agent.js также пишет об этом в консоли браузера. WebView в приложениях отправляют origin "null": добавьте null в список, чтобы принимать их. Нативному Android SDK ничего не нужно.
403account_suspendedАккаунт приостановлен, обычно из-за неоплаченного счёта. Проверьте раздел оплаты.
503temporarily_unavailableКратковременный сбой на нашей стороне. Пропустите действие и повторите позже.

Fail open: если вызов завершился таймаутом или ошибкой, разрешите действие и запишите это в лог. Никогда не позволяйте нашему сбою останавливать ваших пользователей.