Справочник API

API RevRake.

Всё, что платформа оператора отправляет в RevRake, что приходит в ответ и что RevRake отправляет в трекеры партнёров и в собственные системы оператора. О порядке действий читайте в руководстве по интеграции.

Базовые URL

API — это четыре подписанных эндпоинта для платформы оператора, два для записи и два для чтения, и трекинговая ссылка, которую открывают посетители. Подписанные эндпоинты также опубликованы в виде файла OpenAPI 3.1.

ЭндпоинтЗначение
POST https://app.revrake.com/v1/postbackСообщить об одном событии или о массиве событий. С подписью.
POST https://app.revrake.com/v1/filesОтправить ежедневный файл REG или SALES. С подписью.
GET https://app.revrake.com/v1/reportsПрочитать отчёт в JSON или CSV. С подписью, ключом оператора или партнёра.
GET https://app.revrake.com/v1/commissionsПрочитать реестр комиссий, страница за страницей. С подписью, ключом оператора или партнёра.
GET https://app.revrake.com/v1/affiliatesСписок партнёров бренда. С подписью, ключом оператора.
GET https://app.revrake.com/v1/linksСписок трекинговых ссылок. С подписью, ключом оператора или партнёра.
GET https://app.revrake.com/v1/dealsСписок сделок с действующими условиями. С подписью, ключом оператора.
GET https://track.revrake.com/c/{code}Трекинговая ссылка: сохраняет клик и перенаправляет. Без подписи.

Порталы на app.revrake.com используют собственные эндпоинты за сессией вошедшего пользователя. Это не публичный API, и они могут измениться без предупреждения. Отчёты, реестр и строки выплат можно также скачать там в CSV.

Ключи

Ключи бывают двух видов. У каждого есть ID ключа и секрет, и каждый подписывает запросы одинаково. Ключи никому не передаются: у каждой стороны свой.

ID ключа начинается сЧей это ключЧто он может
pb_Оператор. Один активный ключ на бренд, на странице «Интеграция» портала оператора. Увидеть секрет и сменить ключ может администратор рабочего пространства.Отправляет события и файлы. Читает отчёты и реестр всей программы или одного партнёра с affiliate=<number>.
ak_Один партнёр. Каждый партнёр создаёт свой ключ на вкладке «API» своего портала партнёра. Секрет показывается один раз, при создании ключа.Читает отчёты и комиссии только этого партнёра и больше ничего. Отправлять события он не может: /v1/postback и /v1/files отвечают 401 unknown_key.

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

  • Новый ключ сразу отзывает старый — для обоих видов. Партнёр может также отозвать свой ключ и остаться без ключа.
  • Ключ партнёра работает, только пока партнёр одобрен в программе. Иначе чтение отвечает 403 affiliate_inactive.
  • С ключом партнёра параметр affiliate игнорируется, а на by=affiliate возвращается группировка по дням.
  • Лимит частоты чтения считается на ключ.

Аутентификация

Каждый запрос к /v1 подписывается ключом. Каждый запрос содержит три заголовка:

ЗаголовокЗначение
X-RevRake-KeyID вашего ключа. Начинается с pb_ (оператор) или ak_ (партнёр).
X-RevRake-TimestampТекущее Unix-время в секундах. Запрос принимается в пределах пяти минут до или после него.
X-RevRake-SignatureHMAC-SHA256 в hex в нижнем регистре на вашем секрете: от <timestamp>.<body> для POST и от <timestamp>.<path>?<query> для GET.

Чтобы подписать запрос:

  1. Сформируйте тело и сохраните точные байты, которые будете отправлять.
  2. Возьмите текущее Unix-время в секундах, десятичным текстом.
  3. Соедините метку времени, точку (.) и тело.
  4. Вычислите от этого HMAC-SHA256 на вашем секрете и запишите в hex в нижнем регистре.
  5. Отправьте тело без изменений, с тремя заголовками.

Подпись запроса на чтение

У GET нет тела, поэтому подпись считается от цели запроса: пути и строки запроса в точности как при отправке, например 1790000000./v1/reports?by=link&days=7. Если строки запроса нет — от метки времени, точки и пути. Сформируйте адрес один раз, подпишите этот текст и отправьте этот же текст: клиент, который после подписи меняет порядок параметров или перекодирует строку запроса, ломает подпись.

  • Сначала проверяется ключ, затем метка времени, затем подпись.
  • Заголовок Content-Type не обязателен. Передавайте application/json для событий и text/csv для файлов.
  • Сменённый ключ перестаёт работать сразу.

Примеры подписи

В каждом примере одна функция подписи; он отправляет регистрацию, а затем читает отчёт. Замените ID ключа и секрет своими.

curl
KEY="pb_your_key_id"
SECRET="your_secret"
BASE="https://app.revrake.com"

# sign <payload>: hex HMAC-SHA256 of "<timestamp>.<payload>" under the secret
sign() { printf '%s.%s' "$TS" "$1" | openssl dgst -sha256 -hmac "$SECRET" -hex | sed 's/^.* //'; }

# Write: the payload is the body.
TS=$(date +%s)
BODY='{"type":"registration","player_id":"PLR-1001","click_id":"CID_FROM_LANDING_URL"}'
curl -X POST "$BASE/v1/postback" \
  -H "Content-Type: application/json" \
  -H "X-RevRake-Key: $KEY" \
  -H "X-RevRake-Timestamp: $TS" \
  -H "X-RevRake-Signature: $(sign "$BODY")" \
  -d "$BODY"

# Read: the payload is the path and the query, exactly as sent.
TS=$(date +%s)
TARGET='/v1/reports?by=link&days=7'
curl "$BASE$TARGET" \
  -H "X-RevRake-Key: $KEY" \
  -H "X-RevRake-Timestamp: $TS" \
  -H "X-RevRake-Signature: $(sign "$TARGET")"
Node.js
import { createHmac } from 'node:crypto';

const KEY = 'pb_your_key_id';
const SECRET = 'your_secret';
const BASE = 'https://app.revrake.com';

// hex HMAC-SHA256 of "<timestamp>.<payload>" under the secret
function sign(secret, timestamp, payload) {
  return createHmac('sha256', secret).update(`${timestamp}.${payload}`).digest('hex');
}

function headers(payload) {
  const ts = Math.floor(Date.now() / 1000).toString();
  return { 'X-RevRake-Key': KEY, 'X-RevRake-Timestamp': ts, 'X-RevRake-Signature': sign(SECRET, ts, payload) };
}

// Write: the payload is the body. Send the same string you signed.
const body = JSON.stringify({ type: 'registration', player_id: 'PLR-1001', click_id: 'CID_FROM_LANDING_URL' });
const write = await fetch(`${BASE}/v1/postback`, {
  method: 'POST',
  headers: { 'Content-Type': 'application/json', ...headers(body) },
  body,
});
console.log(write.status, await write.json());

// Read: the payload is the path and the query, exactly as sent.
const target = '/v1/reports?by=link&days=7';
const read = await fetch(BASE + target, { headers: headers(target) });
console.log(read.status, await read.json());
Python
import hashlib
import hmac
import json
import time
import urllib.error
import urllib.request

KEY = "pb_your_key_id"
SECRET = "your_secret"
BASE = "https://app.revrake.com"


def sign(secret: str, timestamp: str, payload: bytes) -> str:
    """hex HMAC-SHA256 of "<timestamp>.<payload>" under the secret"""
    return hmac.new(secret.encode(), timestamp.encode() + b"." + payload, hashlib.sha256).hexdigest()


def call(method: str, target: str, body: bytes | None = None):
    ts = str(int(time.time()))
    # Write: the payload is the body. Read: the path and the query, as sent.
    payload = body if body is not None else target.encode()
    headers = {"X-RevRake-Key": KEY, "X-RevRake-Timestamp": ts, "X-RevRake-Signature": sign(SECRET, ts, payload)}
    if body is not None:
        headers["Content-Type"] = "application/json"
    req = urllib.request.Request(BASE + target, data=body, method=method, headers=headers)
    try:
        with urllib.request.urlopen(req, timeout=10) as res:
            return res.status, json.load(res)
    except urllib.error.HTTPError as e:
        return e.code, json.load(e)


event = {"type": "registration", "player_id": "PLR-1001", "click_id": "CID_FROM_LANDING_URL"}
print(*call("POST", "/v1/postback", json.dumps(event).encode()))
print(*call("GET", "/v1/reports?by=link&days=7"))
PHP
<?php
const KEY = 'pb_your_key_id';
const SECRET = 'your_secret';
const BASE = 'https://app.revrake.com';

// hex HMAC-SHA256 of "<timestamp>.<payload>" under the secret
function sign(string $secret, string $timestamp, string $payload): string
{
    return hash_hmac('sha256', $timestamp . '.' . $payload, $secret);
}

function call(string $method, string $target, ?string $body = null): array
{
    $ts = (string) time();
    // Write: the payload is the body. Read: the path and the query, as sent.
    $payload = $body ?? $target;
    $headers = [
        'X-RevRake-Key: ' . KEY,
        'X-RevRake-Timestamp: ' . $ts,
        'X-RevRake-Signature: ' . sign(SECRET, $ts, $payload),
    ];
    $ch = curl_init(BASE . $target);
    curl_setopt_array($ch, [CURLOPT_CUSTOMREQUEST => $method, CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 10]);
    if ($body !== null) {
        $headers[] = 'Content-Type: application/json';
        curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
    }
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $answer = curl_exec($ch);
    return [curl_getinfo($ch, CURLINFO_RESPONSE_CODE), json_decode($answer, true)];
}

$event = ['type' => 'registration', 'player_id' => 'PLR-1001', 'click_id' => 'CID_FROM_LANDING_URL'];
print_r(call('POST', '/v1/postback', json_encode($event)));
print_r(call('GET', '/v1/reports?by=link&days=7'));
Go
package main

import (
	"bytes"
	"crypto/hmac"
	"crypto/sha256"
	"encoding/hex"
	"fmt"
	"io"
	"net/http"
	"strconv"
	"time"
)

const (
	key    = "pb_your_key_id"
	secret = "your_secret"
	base   = "https://app.revrake.com"
)

// sign is the hex HMAC-SHA256 of "<timestamp>.<payload>" under the secret.
func sign(secret, timestamp string, payload []byte) string {
	mac := hmac.New(sha256.New, []byte(secret))
	mac.Write([]byte(timestamp + "."))
	mac.Write(payload)
	return hex.EncodeToString(mac.Sum(nil))
}

func call(method, target string, body []byte) (int, string, error) {
	ts := strconv.FormatInt(time.Now().Unix(), 10)
	// Write: the payload is the body. Read: the path and the query, as sent.
	payload := body
	if body == nil {
		payload = []byte(target)
	}
	req, err := http.NewRequest(method, base+target, bytes.NewReader(body))
	if err != nil {
		return 0, "", err
	}
	req.Header.Set("X-RevRake-Key", key)
	req.Header.Set("X-RevRake-Timestamp", ts)
	req.Header.Set("X-RevRake-Signature", sign(secret, ts, payload))
	if body != nil {
		req.Header.Set("Content-Type", "application/json")
	}
	res, err := (&http.Client{Timeout: 10 * time.Second}).Do(req)
	if err != nil {
		return 0, "", err
	}
	defer res.Body.Close()
	answer, err := io.ReadAll(res.Body)
	return res.StatusCode, string(answer), err
}

func main() {
	event := []byte(`{"type":"registration","player_id":"PLR-1001","click_id":"CID_FROM_LANDING_URL"}`)
	fmt.Println(call("POST", "/v1/postback", event))
	fmt.Println(call("GET", "/v1/reports?by=link&days=7", nil))
}

Тестовый вектор

С этими входными данными ваш код должен выдать ровно такие подписи:

Секрет
test_secret
Метка времени
1791072000
Тело
{"type":"registration","player_id":"PLR-1001","btag":"1001_1"}
Подпись
115d8c73c6069d8953a36ca3a68c114da6232e4ba31889fd519d41ab1350a603
Цель запроса на чтение
/v1/reports?by=link&days=7
Подпись запроса на чтение
ed1ed72dd7ddef22c762f63b8919011e7c36c7214b55b72693c5927fb4b911d0

Лимиты

Это все лимиты, которые продукт сегодня применяет к интеграциям, трекингу и партнёрам, с их значениями. Вход, сброс пароля и заявки тоже ограничены для защиты от злоупотреблений.

ЛимитЗначение
120Запросов на чтение на ключ в минуту: GET /v1/reports и GET /v1/commissions вместе
30 000Запросов с событиями на ключ в минуту: POST /v1/postback, до 1 000 разом
60Файлов на ключ в минуту: POST /v1/files, до 10 разом
4 MBТело POST /v1/postback, одно событие или массив событий
32 MBТело POST /v1/files
1 – 1000Событий в одном массиве
200 000Строк данных в одном файле
300 sРазница между X-RevRake-Timestamp и реальным временем, в любую сторону
24 hНасколько ts и period могут быть в будущем
100Длина player_id, в символах
200Длина txn_id, в символах
0 / 2Десятичных знаков в сумме: столько, сколько у валюты (два у большинства, ни одного у таких валют, как XOF, UGX или JPY)
1 – 365days отчёта
10, 25, 50, 100, 500, 1000per_page реестра: одно из этих значений
1 – 100 000page реестра
100Длина q, в символах; более длинный текст обрезается
200Длина sub1–sub5, каждой UTM-метки и каждого рекламного click ID в трекинговой ссылке, в символах; более длинные значения обрезаются
10Адресов назначения постбэков на партнёра
2000Длина шаблона адреса постбэка, в символах
5 sВремя, за которое трекер должен ответить на постбэк
50Журнал входящих в портале: последние записи за последние 7 дней
2000Длина адреса эндпоинта вебхука, в символах
5 sВремя, за которое эндпоинт вебхука должен ответить
20Неудачных попыток вебхука подряд до отключения эндпоинта
100Доставок на эндпоинт вебхука в журнале доставок
2 – 40Длина промокода: буквы, цифры, дефисы и подчёркивания
32 MBРазмер файла, который RevRake забирает с вашего адреса
60 sВремя, за которое ваш адрес должен отдать файл
0 – 3600 sСекунд после клика для правила о времени регистрации (0 отключает)
0 – 365Дней, после которых открытый фрод-флаг решается сам (0 значит никогда)
1 – 200Флагов, снимаемых или подтверждаемых одним массовым решением
0 – 10 000 (20)Кликов в минуту по одной ссылке с одного адреса, после которых ставится флаг всплеска кликов (0 отключает; 20, если не изменить)
60 + 1 / minТрекинговых ссылок, которые может создать партнёр: 60 сразу, затем одна в минуту. Сверх этого ответ 429 с Retry-After
2 MBРазмер изображения баннера, загружаемого в портале: PNG, JPEG, GIF или WebP

Два эндпоинта записи, POST /v1/postback и POST /v1/files, ограничены на ключ (см. таблицу). Каждый ответ содержит X-RateLimit-Limit и X-RateLimit-Remaining; отказ — это 429 с Retry-After. Отправляйте события в их естественном темпе, а для догрузки истории используйте пакеты. У трекинговой ссылки ограничения частоты нет; необычный всплеск кликов по одной ссылке с одного адреса поднимает флаг фрода, но переход всё равно выполняется.

Лимит частоты чтения

  • Каждый ключ может делать 120 запросов на чтение в минуту. Запас — это корзина на 120: чтение забирает один, и один возвращается каждые полсекунды. Ключ, который простаивал, может сделать 120 чтений сразу; после этого — два в секунду.
  • Каждый ответ на чтение содержит X-RateLimit-Limit (всегда 120) и X-RateLimit-Remaining (сколько чтений осталось прямо сейчас).
  • Сверх лимита ответ — 429 rate_limited с заголовком Retry-After: сколько секунд ждать. Подождите, затем отправьте тот же запрос снова, подписав его свежей меткой времени.
  • Лимит считается на ключ: у ключа оператора и у ключа каждого партнёра свой запас.
HTTP/1.1 200 OK
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 117
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 120
X-RateLimit-Remaining: 0
Retry-After: 1

{"error":"rate_limited","message":"Too many requests: at most 120 reads a minute per key. One more is allowed every half second; wait the seconds in Retry-After and try again."}

Обработка 429

// read(target) signs one GET with a fresh timestamp and sends it,
// as in the signing samples.
async function readWithRetry(target, tries = 5) {
  for (let i = 0; i < tries; i++) {
    const res = await read(target);
    if (res.status !== 429) return res;
    const seconds = Number(res.headers.get('Retry-After')) || 1;
    await new Promise((resolve) => setTimeout(resolve, seconds * 1000));
  }
  throw new Error('still rate limited after ' + tries + ' tries');
}

POST /v1/postback

Сообщает об одном событии с платформы оператора. Тело — JSON-объект с полем type и полями этого типа или JSON-массив таких объектов (пакетная отправка).

POST https://app.revrake.com/v1/postback
  • type — одно из значений: registration, deposit, chargeback, ngr.
  • Поле, не перечисленное для типа, отклоняется с 422, так что опечатка никогда не проходит молча.
  • ts — время события в формате RFC 3339 (2026-10-04T08:15:00Z). Если его нет, берётся время запроса. В нём должно быть смещение от UTC (Z или +03:00); время без смещения отклоняется. Оно не может быть в будущем больше чем на сутки.
  • Сумма — десятичное число, JSON-текстом или JSON-числом: "25.00" или 25.5. Без разделителя тысяч, без экспоненты и не больше десятичных знаков, чем у валюты.
  • currency — трёхбуквенный код ISO 4217. Нижний регистр принимается. Если не передан, берётся валюта отчётности рабочего пространства.
  • У текстовых значений обрезаются пробелы в начале и в конце, кроме click_id и btag: передавайте их ровно в том виде, в каком они пришли на лендинг.

registration

Новый игрок. Передайте click_id, btag, promo_code или несколько из них; без них игрок записывается как неатрибутированный. Игрок атрибутируется один раз, здесь. Ответ: attribution.

{"type":"registration","player_id":"PLR-1001","click_id":"01K6QF3M8Z5T7W9XB2C4D6E8GH","btag":"1001_1"}
ПолеТипОбязательноПримерЗначение
player_idstringда"PLR-1001"Ваш ID игрока. До 100 символов. Ключ события.
click_idstringнет"01K6QF3M8Z5T7W9XB2C4D6E8GH"cid, с которым пришёл игрок: 26 символов, буквы и цифры; в верхнем или нижнем регистре.
btagstringнет"1001_1"btag, который ваша платформа сохранила у игрока: <номер партнёра>_<номер ссылки>, только цифры.
promo_codestringнет"GARAGE50"Промокод, который игрок ввёл при регистрации. Регистр не важен. Атрибутирует игрока, только если этого не сделали click_id и btag.
email_hashstringнет"9f86d081…0f00a08"SHA-256 от e-mail в нижнем регистре, в hex. Используется только проверкой на самореферал.
email_domainstringнет"example.com"Домен e-mail игрока, часть после @ (example.com). Используется только правилом одноразового email. Передавайте только домен: если придёт адрес целиком, у игрока сохранится только домен, но журнал входящих всё равно покажет запрос в том виде, в каком он пришёл.
ipstringнет"203.0.113.7"IP-адрес при регистрации. Он хешируется и используется только проверкой на самореферал и для поиска клика, соответствующего btag.
countrystringнет"KE"Страна игрока: две буквы, ISO 3166-1 alpha-2 (GB, KE). Строчные буквы принимаются. Значение не из двух букв оставляет игрока без страны. Без этого поля берётся страна клика, который привёл игрока. В сделке можно указать страны, за которые она не платит.
tsstringнет"2026-10-04T08:15:00Z"Когда игрок зарегистрировался. От этого времени отсчитывается окно атрибуции.
{
  "status": "accepted",
  "event_type": "registration",
  "event_id": "0199b2c4-6f1e-7a53-9d0c-2b8f4e1a7c33",
  "attribution": {
    "attributed": true,
    "reason": "click",
    "affiliate_number": 1001,
    "link_number": 1,
    "click_id": "01K6QF3M8Z5T7W9XB2C4D6E8GH",
    "policy_version": 1,
    "window_days": 30,
    "model": "last_click"
  }
}

deposit

Отправляйте событие deposit для каждого депозита с ID транзакции в txn_id. Сделка определяет, сравнивать ли минимум CPA с первым депозитом или с суммой депозитов за вычетом чарджбэков. При выполнении условия создаётся одна комиссия CPA на игрока, в холде.

{"type":"deposit","player_id":"PLR-1001","txn_id":"TX-88213","amount":"25.00","currency":"KES","first":true}
ПолеТипОбязательноПримерЗначение
player_idstringда"PLR-1001"Ваш ID игрока. До 100 символов.
txn_idstringда"TX-88213"Ваш ID транзакции. До 200 символов. Ключ события.
amountstring | numberда"25.00"Сумма депозита, больше нуля.
currencystringнет"KES"Валюта депозита. Принимается любая валюта.
tsstringнет"2026-10-04T08:20:00Z"Когда был сделан депозит. Определяет, какая версия сделки и курс какого дня применяются.
firstbooleanнетtruetrue, если это первый депозит игрока. Если не передано, депозит считается первым, когда RevRake не знает более ранних депозитов этого игрока.
{
  "status": "accepted",
  "event_type": "deposit",
  "event_id": "0199b2c9-03aa-7e10-b6d2-91c07f5e2a18",
  "commission": {
    "effect": "created",
    "type": "cpa",
    "amount_minor": 4000,
    "status": "hold"
  }
}

chargeback

Отправьте событие chargeback с собственным txn_id и txn_id исходного депозита в ref_txn_id. Оно отменяет весь депозит. При накопительном CPA комиссия отзывается, только если оставшаяся зачётная сумма становится ниже минимума: комиссия в холде отклоняется, для одобренной или выплаченной добавляется строка отмены.

{"type":"chargeback","txn_id":"CB-5001","ref_txn_id":"TX-88213"}
ПолеТипОбязательноПримерЗначение
txn_idstringда"CB-5001"Ваш ID самого чарджбэка. До 200 символов. Ключ события.
ref_txn_idstringда"TX-88213"txn_id депозита, по которому прошёл чарджбэк.
player_idstringнет"PLR-1001"Необязательно. Если указан, должен совпадать с игроком исходного депозита.
tsstringнет"2026-10-09T11:00:00Z"Когда произошёл чарджбэк.
{
  "status": "accepted",
  "event_type": "chargeback",
  "event_id": "0199cc10-7b2d-7c41-a3f0-5d2e8b9c1f47",
  "commission": {
    "effect": "cancelled",
    "type": "cpa",
    "amount_minor": 4000,
    "status": "rejected"
  }
}

ngr

Чистый игровой доход (NGR) игрока за день или месяц. По нему начисляется RevShare той версии сделки, которая действует на конец периода, в холде. Игрок должен быть зарегистрирован. Ответ: commission.

{"type":"ngr","player_id":"PLR-1001","period":"2026-10-03","amount":"118.40","currency":"KES"}
ПолеТипОбязательноПримерЗначение
player_idstringда"PLR-1001"Ваш ID игрока. До 100 символов.
periodstringда"2026-10-03"День (YYYY-MM-DD) или месяц (YYYY-MM), за который указана сумма. Месяц и его первый день являются разными периодами. Не больше чем на сутки в будущем.
amountstring | numberда"118.40"Чистый игровой доход (NGR) за период. Отрицательный, если игрок выиграл.
currencystringнет"KES"Валюта суммы.
ggrstring | numberнет"240.00"Необязательно. Валовый игровой доход (GGR) за период, в той же валюте. Показывается партнёру; на комиссию не влияет.
bonusesstring | numberнет"80.00"Необязательно. Бонусы, вычтенные из валового дохода. Только для показа.
feesstring | numberнет"21.60"Необязательно. Комиссии, вычтенные из валового дохода, например платёжные или платформенные. Только для показа.
taxesstring | numberнет"20.00"Необязательно. Налоги, вычтенные из валового дохода. Только для показа.
tsstringнет"2026-10-04T02:00:00Z"Когда цифра была передана.
{
  "status": "accepted",
  "event_type": "ngr",
  "event_id": "0199b2d1-5c0e-7b42-8a17-3e9d6f0c4b21",
  "commission": {
    "effect": "created",
    "type": "revshare",
    "amount_minor": 2960,
    "status": "hold"
  }
}

click_id, btag, promo_code или player_id, содержащие { или }, отклоняются: это значит, что ваша платформа отправила незаполненный плейсхолдер.

Ответ

На событие, которое сохранено или уже было сохранено, возвращается 200 и JSON-объект. Неприменимые поля опускаются.

ПолеТипЗначение
statusstringaccepted или duplicate, если событие уже было сохранено.
event_typestringЗначение type, которое вы отправили.
event_idstringID сохранённого события в RevRake, UUID. Один и тот же при каждой повторной отправке.
attributionobjectДля регистрации: решение.
attribution.attributedbooleanПринадлежит ли игрок какому-либо партнёру.
attribution.reasonstringПочему. См. таблицу ниже.
attribution.affiliate_numberintegerПартнёр. Только если игрок атрибутирован.
attribution.link_numberintegerСсылка партнёра. Только если игрок атрибутирован.
attribution.click_idstringНайденный клик, если он есть.
attribution.policy_versionintegerВерсия правила атрибуции бренда, по которой принято решение.
attribution.window_daysintegerОкно атрибуции этой версии, в днях.
attribution.modelstringlast_click или first_click: модель этой версии.
commissionobjectДля депозита, чарджбэка и ngr: что событие изменило в реестре.
commission.effectstringcreated, cancelled (комиссия в холде отклонена), reversed (добавлена строка отмены) или none.
commission.typestringcpa, revshare, adjustment или reversal.
commission.amount_minorintegerСумма в минимальных единицах валюты сделки (4000 — это 40.00). Отрицательная для отмены и для корректировки в меньшую сторону.
commission.statusstringhold, approved или rejected.
commission.reasonstringПочему ничего не создано, когда effect равен none. См. таблицу ниже.
waiting_for_playerbooleantrue для депозита, игрок которого ещё не зарегистрирован. Депозит сохраняется и оценивается, когда придёт регистрация.
duplicate_ofstringДля сопоставления первого депозита между онлайн-событием и старым дневным файлом: предыдущий event_id. Текущие сводки SALES используют дневное покрытие и сохраняют ID каждой реальной транзакции.
detailstringВместе с duplicate_of: предложение о том, какой более ранний депозит повторяет этот.
{
  "status": "accepted",
  "event_type": "deposit",
  "event_id": "0199b2c9-03aa-7e10-b6d2-91c07f5e2a18",
  "waiting_for_player": true
}
{
  "status": "duplicate",
  "event_type": "deposit",
  "event_id": "0199b31f-8c02-7a66-b4e1-2d7f9a3c6e15",
  "duplicate_of": "0199b2c9-03aa-7e10-b6d2-91c07f5e2a18",
  "detail": "The same deposit (TX-88213) was already reported through the API; this one adds nothing."
}
{
  "status": "duplicate",
  "event_type": "deposit",
  "event_id": "0199b2ca-11d4-7f09-8c55-0a6e2d4b7f90",
  "commission": { "effect": "none", "reason": "not_first" }
}

Комиссия создаётся со статусом hold. Она одобряется автоматически, когда заканчивается холд сделки, если её ничто не удерживает: открытый фрод-флаг, неодобренный партнёр или отсутствующий курс.

Причины атрибуции

Сначала проверяется click ID. Если он не из ваших, проверяется btag. Если правило говорит, что побеждает btag, и btag совпадает со ссылкой, первым проверяется btag. Btag, совпавший со ссылкой, атрибутирует игрока, даже если клик не найден. Промокод проверяется последним, только если ни click ID, ни btag не атрибутировали игрока. Правило, его окно и то, что из двух побеждает, задаются на странице «Интеграция»; каждое изменение становится новой версией. Если политика отдаёт приоритет промокоду, совпавший с ссылкой код проверяется раньше обоих, а несовпавший возвращает к ним. Сделка может задать своё окно, которое заменяет окно политики для кликов по ссылкам её партнёров.

reasonЗначение
clickАтрибутированClick ID совпал с кликом в пределах окна.
first_clickАтрибутированПравило: первый клик. Click ID совпал с кликом в пределах окна, но засчитан более ранний клик того же посетителя (тот же адрес и устройство) в пределах окна.
btag_clickАтрибутированBtag совпал со ссылкой, и по ней найден клик в пределах окна.
btag_onlyАтрибутированBtag совпал со ссылкой; клика в пределах окна не найдено.
promo_codeАтрибутированНи click ID, ни btag не атрибутировали игрока, а промокод совпал с кодом одобренного партнёра.
no_tagНе атрибутированВ регистрации не было ни click ID, ни btag.
unknown_clickНе атрибутированClick ID не из ваших, а btag не передан.
unknown_btagНе атрибутированBtag имеет неверный формат или не соответствует ни одной ссылке.
outside_windowНе атрибутированКлик старше окна атрибуции или позже регистрации.
affiliate_inactiveНе атрибутированПартнёр не одобрен или не был одобрен в момент клика.
unknown_promo_codeНе атрибутированПередан только промокод, и он не совпадает ни с одним из ваших кодов.
promo_code_retiredНе атрибутированПередан только промокод, и он выведен.

Почему комиссия не создана

commission.reasonЗначение
unattributedИгрок не принадлежит ни одному партнёру.
not_firstНе первый депозит игрока.
already_earnedCPA по этому игроку уже начислена. Второй «первый» депозит ничего не приносит и создаёт флаг.
no_deal_versionУ партнёра нет сделки, или у сделки не было версии на момент события.
country_blockedИгрок из страны, за которую сделка не платит. Игрок остаётся записанным и атрибутированным.
no_cpa_in_dealСделка не предусматривает CPA.
below_thresholdПервый депозит или накопительная сумма депозитов за вычетом чарджбэков ниже минимума сделки, согласно базе CPA.
no_commissionДля чарджбэка: по депозиту ничего не было начислено.
no_revshare_in_dealДля ngr: сделка не предусматривает RevShare.
fx_rate_missingДля ngr: курса за этот период ещё нет. Отчёт сохраняется и оценивается, когда курс появится.
unchangedДля ngr: исправленная цифра, которая ничего не меняет в комиссии.

Пакетная отправка

Телом может быть JSON-массив от 1 до 1000 событий, отправленный на тот же эндпоинт с теми же заголовками. Подпись считается от всего массива. События обрабатываются по порядку, каждое отдельно, так что одно отклонённое событие не останавливает остальные.

На массив, который удалось прочитать, возвращается 200 — даже если все события в нём отклонены. Смотрите на счётчики.

[
  {"type":"deposit","player_id":"PLR-1001","txn_id":"TX-88213","amount":"25.00","first":true},
  {"type":"ngr","player_id":"PLR-1001","period":"2026-10-03","amount":"118.40"},
  {"type":"ngr","player_id":"PLR-1002","period":"October","amount":"-12.50"}
]
{
  "results": [
    {
      "index": 0,
      "status": "accepted",
      "event_type": "deposit",
      "event_id": "0199b2c9-03aa-7e10-b6d2-91c07f5e2a18",
      "commission": { "effect": "created", "type": "cpa", "amount_minor": 4000, "status": "hold" }
    },
    {
      "index": 1,
      "status": "duplicate",
      "event_type": "ngr",
      "event_id": "0199b2d1-5c0e-7b42-8a17-3e9d6f0c4b21",
      "commission": { "effect": "created", "type": "revshare", "amount_minor": 2960, "status": "hold" }
    },
    {
      "index": 2,
      "status": "rejected",
      "field": "period",
      "message": "period must be a day (2026-10-03) or a month (2026-10), not in the future."
    }
  ],
  "accepted": 1,
  "duplicate": 1,
  "rejected": 1
}
ПолеТипЗначение
resultsarrayПо одной записи на событие, в порядке отправки.
results[].indexintegerПозиция события в массиве, начиная с 0.
results[].statusstringaccepted, duplicate или rejected.
results[].event_typestringКак в ответе на одно событие. Отсутствует у отклонённого события.
results[].event_idstringКак в ответе на одно событие. Отсутствует у отклонённого события.
results[].attributionobjectКак в ответе на одно событие.
results[].commissionobjectКак в ответе на одно событие.
results[].waiting_for_playerbooleanКак в ответе на одно событие.
results[].fieldstringДля отклонённого события: поле, которое нужно исправить.
results[].messagestringДля отклонённого события: что исправить.
acceptedintegerСколько событий сохранено.
duplicateintegerСколько уже было сохранено.
rejectedintegerСколько отклонено.

POST /v1/files

Отправляет ежедневный CSV-файл: альтернатива его загрузке на странице «Интеграция» или тому, чтобы RevRake забирал его с адреса, по которому его публикует ваша платформа. Тело запроса: сам файл; заголовки и подпись те же, что у события, а подпись считается от метки времени и файла. Имя файла передаётся в параметре строки запроса filename; оно показывается в портале и больше нигде не используется.

POST https://app.revrake.com/v1/files?filename=sales-2026-10-03.csv

Строка заголовка определяет тип файла: файл со столбцом registration_date — это файл REG, со столбцом activitydate — файл SALES. Имена столбцов сопоставляются без учёта регистра. Столбцы, не перечисленные ниже, могут оставаться в файле; они игнорируются.

Форматы дат: YYYY-MM-DD, YYYY-MM-DD HH:MM:SS, YYYY-MM-DDTHH:MM:SS, RFC 3339 или YYYY/MM/DD. Без смещения UTC применяется часовой пояс файлов из настроек рабочего пространства (по умолчанию UTC). Время со смещением задаёт точный момент; для SALES используется его календарный день в часовом поясе файлов. Порядок дня и месяца не угадывается: 30/09/2026 отклоняется.

Файл REG: одна строка на зарегистрированного игрока

СтолбецОбязательноЗначение
registration_dateдаКогда игрок зарегистрировался. Становится ts.
player_idдаВаш ID игрока.
btagдаBtag, сохранённый у игрока. Может быть пустым: тогда игрок не атрибутируется, если его не атрибутирует промокод.
promo_codeнетНеобязательная. Промокод, который игрок ввёл при регистрации; используется как promo_code регистрации.
player_countryнетНеобязательная. Двухбуквенный код страны игрока (ISO 3166-1 alpha-2); используется как country регистрации. Пусто: страна клика.
brand_name,registration_date,btag,promo_code,player_id,player_country
Example,2026-10-03,1001_1,,PLR-1001,KE
Example,2026-10-03,,,PLR-1002,KE
Example,2026-10-03,,GARAGE50,PLR-1003,KE

Файл SALES: одна строка на игрока в день

СтолбецОбязательноЗначение
activitydateдаДень активности в часовом поясе файлов рабочего пространства.
player_idдаВаш ID игрока.
currencyдаВалюта сумм в строке. Пусто: валюта отчётности рабочего пространства.
depositsдаОбщая сумма депозитов за день, включая первый депозит, если он сделан в этот день. Не сумма за всё время; чарджбэки не вычитайте.
first_deposit_amountдаСумма первого депозита только в день его совершения; в остальные дни — ноль. Уже включена в deposits и повторно не прибавляется. Не может превышать общую сумму депозитов за день.
chargebackдаСумма чарджбэков за этот день активности, отдельно от общей суммы депозитов. Не сумма за всё время. Уменьшает накопительную сумму для CPA, но не указывает конкретную транзакцию.
*_net_revenueнетКаждый столбец с именем net_revenue или с именем, которое заканчивается на _net_revenue. Заполненные ячейки суммируются в чистый доход игрока за день, который передаётся как ngr. Строка, где ни одна из них не заполнена, о доходе не сообщает.
*_gross_revenueнетНеобязательно. Столбцы с именем gross_revenue или с именем, которое заканчивается на _gross_revenue, суммируются в ggr дневного ngr. Показывается только партнёру.
*_bonusнетНеобязательно. Столбцы с именем bonus или с окончанием _bonus, суммируются в bonuses. Только для показа.
*_feesнетНеобязательно. Столбцы с именем fees или с окончанием _fees, суммируются в fees. Только для показа.
*_taxesнетНеобязательно. Столбцы с именем taxes или с окончанием _taxes, суммируются в taxes. Только для показа.
brand_name,activitydate,player_id,btag,currency,deposits,first_deposit_amount,chargeback,casino_net_revenue,sports_net_revenue
Example,2026-10-03,PLR-1001,1001_1,KES,3500.00,2500.00,0,118.40,0
Example,2026-10-03,PLR-1002,,KES,900.00,0,0,-12.50,
  • Каждая строка SALES сохраняет дневную денежную сводку и, если заполнены ячейки выручки, отдельное событие NGR. Они обрабатываются независимо: отклонение денежной сводки не отменяет принятую выручку, и наоборот. Проверяйте все проблемы в ответе.
  • Одна сводка на бренд, игрока и день активности; первая принятая валюта фиксируется. Одинаковые денежные значения считаются повтором даже после переименования файла или перестановки строк. Изменение сумм, валюты или часовых границ принятого дня вызывает конфликт, в том числе при изменении нулей. Записанные деньги остаются неизменными.
  • deposits, first_deposit_amount и chargeback — обязательные столбцы. Пустая ячейка означает ноль. Суммы должны быть неотрицательными десятичными числами с точностью валюты строки. Согласуйте эти определения с платформой до подключения экспорта.
  • Отправляйте REG перед SALES. Денежные сводки, полученные раньше, сохраняются и рассчитываются при поступлении регистрации. NGR неизвестного игрока отклоняется: после REG повторите SALES или NGR. Сохранённая денежная сводка будет обработана как повтор.
  • Сводка покрывает отдельные постбэки за её день активности и в её валюте в часовом поясе файлов, без двойного суммирования. ID транзакций остаются доступны для ссылок. Известные депозиты или чарджбэки сверх сводки, а также противоречивые данные о первом депозите вызывают конфликт.
  • Для накопительного CPA депозиты за вычетом чарджбэков должны достичь минимума сделки. Каждый дневной денежный поток использует курс своей даты активности; отдельные постбэки — своего дня UTC. Без курса расчёт остаётся в холде с fx_rate_missing. Отсутствие курса чарджбэка блокирует выплату с chargeback_fx_missing до сверки, в том числе для комиссий, уже включённых в выплату.
  • При CPA по первому депозиту агрегированный чарджбэк может не указывать отменённый депозит. Неоднозначная денежная сводка зарегистрированного игрока отклоняется. Если она пришла до REG, сводка сохраняется и регистрация принимается, но созданный CPA остаётся в холде с chargeback_reference_missing. Для проверки ссылки на транзакцию отправьте чарджбэк, указав ID транзакции исходного депозита в ref_txn_id.
  • Выручка независима от неизменяемых денежных итогов: изменение дневного NGR считается корректировкой, а разница комиссии записывается отдельным корректирующим начислением.

Ответ

Читаемый файл возвращает 200. Счётчики относятся к событиям, а не только строкам: строка SALES может отдельно сохранить денежную сводку и NGR, в том числе с частичным успехом. Всегда проверяйте rejected и problems.

{
  "id": "0199b31e-2a40-7d18-9b6c-4f1e7a2c5d03",
  "filename": "sales-2026-10-03.csv",
  "kind": "sales",
  "uploaded_at": "2026-10-04T02:00:07Z",
  "rows_total": 2,
  "accepted": 3,
  "duplicates": 0,
  "rejected": 1,
  "skipped": 0,
  "problems": ["line 3: Player PLR-1002 is not registered. Send the registration first."]
}
ПолеТипЗначение
idstringID этого импорта в RevRake.
filenamestringИмя, которое вы передали, или reg.csv / sales.csv.
kindstringreg или sales.
uploaded_atstringКогда файл получен.
rows_totalintegerСтрок данных в файле.
acceptedintegerСобытий сохранено.
duplicatesintegerСобытий, которые уже были сохранены.
rejectedintegerСтрок или событий отклонено. Каждое есть в журнале входящих вместе с самой строкой.
skippedintegerСтрок, в которых нечего записывать.
problemsarray of stringПервые 20 отклонённых строк в виде line N: reason. Опускается, если их нет.

GET /v1/reports

Возвращает отчёт страницы «Отчёты»: клики, помеченные клики, регистрации, первые депозиты и заработок, сгруппированные по одному признаку, за дни по сегодняшний в часовом поясе рабочего пространства. Цифры за сегодня обновляются при запросе отчёта, на загруженной программе — не чаще раза в 30 секунд.

GET https://app.revrake.com/v1/reports?by=link&days=7
ПараметрТипПримерЗначение
bystringlinkКак группируются строки: day, link, sub1, country или affiliate. По умолчанию day. Если задан affiliate, на by=affiliate возвращается группировка day.
daysinteger7Сколько дней, считая сегодняшний: от 1 до 365. По умолчанию 30.
fromstring2026-09-01Первый день любого периода, YYYY-MM-DD в часовом поясе рабочего пространства. С from или to параметр days игнорируется. Не больше 366 дней.
tostring2026-09-30Последний день периода, включительно. По умолчанию сегодня.
affiliateinteger1001Номер партнёра. Ограничивает отчёт этим партнёром. Только для ключа оператора; с ключом партнёра игнорируется: он всегда читает своего партнёра.
tagstringInfluencersНазвание группы, как на странице «Группы» (повторите для нескольких: любая из них). Только с ключом оператора; игнорируется с affiliate или ключом партнёра. Неизвестное название — 422 unknown_tag.
formatstringcsvcsv возвращает CSV-файл вместо JSON.
{
  "by": "link",
  "from": "2026-09-28",
  "to": "2026-10-04",
  "currency": "KES",
  "rows": [
    {
      "key": "0199a7f0-41c2-7e55-b1d9-6c3a8e2f7b10",
      "label": "telegram-october",
      "clicks": 1840,
      "flagged_clicks": 212,
      "registrations": 96,
      "ftds": 31,
      "earnings_minor": 12400000
    }
  ],
  "total": {
    "key": "",
    "label": "",
    "clicks": 1840,
    "flagged_clicks": 212,
    "registrations": 96,
    "ftds": 31,
    "earnings_minor": 12400000
  }
}
ПолеТипЗначение
bystringИспользованная группировка.
fromstringПервый день отчёта, YYYY-MM-DD.
tostringПоследний день: сегодня в часовом поясе рабочего пространства или указанный вами to.
currencystringВалюта отчётности рабочего пространства. Заработок указан в ней.
rowsarrayПо одной записи на группу.
rows[].keystringЧто идентифицирует группу: день, ID ссылки или партнёра в RevRake, значение sub1 или двухбуквенный код страны.
rows[].labelstringТекст, который портал показывает для группы: день, название кампании ссылки, значение sub1, страна или имя и номер партнёра.
rows[].clicksintegerЧистые клики.
rows[].flagged_clicksintegerКлики, помеченные как боты, повторы, всплески или как клики неодобренного партнёра. В clicks не входят.
rows[].registrationsintegerАтрибутированные игроки.
rows[].ftdsintegerПервые депозиты.
rows[].earnings_minorintegerНачисленные комиссии в минимальных единицах валюты отчётности, по курсу дня, когда каждая была начислена.
totalobjectСумма строк, в том же виде, что и строка.

В формате CSV

С format=csv ответ — файл. Его первый столбец назван по группировке и содержит подпись группы; далее идут clicks, flagged_clicks, registrations, first_deposits и earnings_<currency> десятичным числом. Последняя строка — итог.

link,clicks,flagged_clicks,registrations,first_deposits,earnings_KES
telegram-october,1840,212,96,31,124000.00
total,1840,212,96,31,124000.00

GET /v1/commissions

Возвращает одну страницу реестра комиссий, сначала новые, если вы не задали другую сортировку. Суммы в строках никогда не редактируются, и строки никогда не удаляются, но status строки меняется после её записи: hold, затем approved, затем paid — или rejected. Синхронизация должна перечитывать период и обновлять строки по id, а не только загружать новые.

GET https://app.revrake.com/v1/commissions?from=2026-09-01&to=2026-10-01&per_page=500
ПараметрТипПримерЗначение
statusstringapprovedhold, approved, paid или rejected. По умолчанию: все.
fromstring2026-09-01Только строки, время которых не раньше указанного: RFC 3339 или день YYYY-MM-DD в UTC.
tostring2026-10-01Только строки, время которых раньше указанного. Те же форматы.
affiliateinteger1001Номер партнёра. Ограничивает строки, totals и owed этим партнёром. Только для ключа оператора; с ключом партнёра игнорируется.
tagstringInfluencersНазвание группы, как на странице «Группы» (повторите для нескольких: любая из них). Только с ключом оператора; игнорируется с affiliate или ключом партнёра. Неизвестное название — 422 unknown_tag.
qstringPLR-1001Строки, в которых ID игрока или имя партнёра содержит этот текст. До 100 символов.
sortstringwhenwhen, affiliate, player, status, deposit или commission. По умолчанию when.
dirstringascasc или desc. По умолчанию desc.
pageinteger2Страница, начиная с 1. По умолчанию 1.
per_pageinteger50010, 25, 50, 100, 500 или 1000. По умолчанию 25.
{
  "currency": "KES",
  "totals": { "hold": 1240000, "approved": 3720000, "paid": 9800000 },
  "owed": { "KES": { "hold": 1240000, "approved": 3720000, "paid": 9800000 } },
  "period": true,
  "commissions": [
    {
      "id": "0199b2c9-0a11-7c3e-9f20-7d4b1e6a2c58",
      "occurred_at": "2026-09-14T08:20:00Z",
      "type": "cpa",
      "currency": "KES",
      "gross_currency": "KES",
      "reporting_minor": 400000,
      "affiliate_name": "Odds Garage",
      "affiliate_number": 1001,
      "player_ref": "PLR-1001",
      "deal_name": "CPA 4000",
      "deal_version": 2,
      "gross_minor": 250000,
      "rate_snapshot": 400000,
      "amount_minor": 400000,
      "status": "approved",
      "status_reason": "",
      "hold_until": "2026-10-14T08:20:00Z",
      "status_note": ""
    }
  ],
  "total": 1,
  "page": 1,
  "per_page": 500
}
ПолеТипЗначение
currencystringВалюта отчётности рабочего пространства.
totalsobjectСумма по каждому статусу, в минимальных единицах валюты отчётности: по всему реестру или за период, если указан from или to. Другие фильтры её не ограничивают, кроме affiliate. Строки, которые ещё ждут курса, в неё не входят.
owedobjectСумма по каждой валюте и статусу, в собственной валюте каждой комиссии: сколько вы должны. По тем же строкам, что и totals.
periodbooleantrue, если указан from или to: тогда totals и owed относятся только к этому периоду.
commissionsarrayСтроки этой страницы.
totalintegerСколько строк соответствует фильтрам.
pageintegerВозвращённая страница.
per_pageintegerИспользованное число строк на странице.

Строка комиссии

ПолеТипЗначение
idstringID строки в RevRake, UUID. Никогда не меняется: обновляйте по нему.
occurred_atstringКогда комиссия была начислена: время депозита, конец периода дохода или время чарджбэка.
typestringcpa, revshare, adjustment, reversal или tier.
amount_minorintegerКомиссия в минимальных единицах валюты currency. Отрицательная для отмены и для корректировки в меньшую сторону.
currencystringВалюта комиссии: валюта сделки.
reporting_minorinteger | nullКомиссия в валюте отчётности рабочего пространства, по курсу дня, когда она была начислена. null, пока этого курса нет.
gross_minorintegerДепозит или чистый доход, с которого начислена комиссия, в минимальных единицах валюты gross_currency.
gross_currencystringВалюта депозита или дохода.
rate_snapshotintegerПрименённые условия: сумма CPA в минимальных единицах или доля RevShare в сотых долях процента (2500 — это 25%).
statusstringhold, approved, paid или rejected. См. статусы комиссий.
status_reasonstringПочему строка всё ещё в холде или была отклонена. В остальных случаях пусто. Все значения — в таблице причин.
status_notestringКомментарий оператора к отозванной комиссии, в том виде, в каком его видит партнёр. В остальных случаях пусто.
hold_untilstring | nullКогда заканчивается холд. null для отмены.
affiliate_numberintegerНомер партнёра.
affiliate_namestringИмя партнёра.
player_refstringВаш ID игрока.
deal_namestringСделка.
deal_versionintegerВерсия сделки, по которой рассчитана строка.

Списки программы: партнёры, ссылки, сделки

Ваш бэкенд может получить программу в том виде, в каком её показывает кабинет: с подписью, как и другие чтения, и в том же лимите. GET /v1/affiliates и GET /v1/deals требуют ключ оператора; с ключом партнёра они отвечают 403 operator_key_required. GET /v1/links отдаёт ссылки бренда или одного партнёра с affiliate=<номер>; с ключом партнёра — только его ссылки.

Списки разбиты на страницы параметрами page (с 1) и per_page (от 1 до 500, по умолчанию 100) и содержат total. GET /v1/affiliates принимает также status: pending, approved, rejected или suspended. Создавать партнёров и ссылки через API пока нельзя: расскажите, для чего вам это нужно.

GET https://app.revrake.com/v1/links?affiliate=1001&per_page=100

Каждый партнёр

ПолеТипЗначение
numberintegerНомер партнёра, первая часть btag; у ссылки — номер ссылки, вторая часть.
namestringИмя партнёра.
emailstringEmail партнёра.
statusstringpending, approved, rejected или suspended.
dealstringНазвание сделки партнёра; пусто до одобрения.
created_atstringКогда создан, RFC 3339.
decided_atstring | nullКогда заявка одобрена или отклонена, либо аккаунт приостановлен; до этого null.

Каждая ссылка

ПолеТипЗначение
affiliate_numberintegerНомер партнёра, которому принадлежит ссылка.
numberintegerНомер партнёра, первая часть btag; у ссылки — номер ссылки, вторая часть.
codestringКод в адресе ссылки.
urlstringТрекинговая ссылка на проверенном трекинговом домене бренда или на общем.
btagstring<affiliate_number>_<number>.
campaignstringМетка кампании ссылки.
landing_pathstring | nullСтраница вашего сайта, на которую ведёт ссылка; null — страница бренда по умолчанию.
subsstring[5]sub1–sub5, заданные на ссылке; пустые строки, если не заданы.
promo_codestring | nullПромокод, если ссылка создана для него; иначе null.
vanity_urlstring | nullКороткий адрес /go/<имя>, если партнёр его задал; иначе null.
created_atstringКогда создан, RFC 3339.

Каждая сделка

ПолеТипЗначение
namestringИмя партнёра.
currencystringВалюта, в которой сделка начисляет и выплачивает.
listedbooleanПоказывает ли сделку публичная страница заявки.
defaultbooleanПолучают ли эту сделку новые партнёры.
versionintegerДействующая сейчас версия сделки.
effective_atstringКогда эта версия вступила в силу, RFC 3339.
termsobjectУсловия этой версии: суммы в минимальных единицах, доли в базисных пунктах (2500 = 25 %), дни удержания, правило убыточных месяцев, собственное окно атрибуции сделки, уровни.

Выгрузка в хранилище данных

Настраивается на странице «Интеграция»: каждую ночь RevRake записывает предыдущий день каждого бренда в ваш собственный бакет любого S3-совместимого сервиса по пути <папка>/<бренд>/<ГГГГ-ММ-ДД>/; день считается в часовом поясе рабочего пространства. Четыре CSV-файла, сжатых gzip (UTF-8, строка заголовков, кавычки по RFC 4180), затем manifest.json. Манифест пишется последним: загружайте день, когда он появился, и сверяйте rows, bytes и sha256 каждого файла.

Строка относится к дню, когда она поступила (клик — когда был сделан), поэтому опоздавший ежедневный файл попадает в день поступления и не теряется. Время — RFC 3339 в UTC с миллисекундами; суммы — десятичные числа в своей валюте. Статусы — на момент выгрузки: статус комиссии потом меняется, поэтому за текущим снова читайте GET /v1/commissions. Неудачный день повторяется каждый час и догоняется до семи дней назад; повторная выгрузка дня перезаписывает его файлы. В конец файла могут добавляться новые столбцы; schema_version в манифесте меняется, когда загрузчик должен измениться.

manifest.json: schema_version, workspace, brand, day, timezone, from и to (границы дня в UTC), generated_at и files: для каждого name, rows, bytes, sha256 (сжатого файла).

clicks.csv.gz: все клики по ссылкам бренда за день, включая помеченные.

ПолеТипЗначение
click_idstringID клика, как он передаётся на посадочную страницу и в постбэках.
clicked_atstringКогда был клик.
affiliate_numberintegerНомер партнёра.
link_numberintegerНомер ссылки.
btagstring<affiliate_number>_<link_number>.
countrystringДвухбуквенный код страны; пусто, если неизвестна.
devicestringdesktop, mobile, tablet или bot — по браузеру.
osstringОперационная система по браузеру.
browserstringБраузер.
sub1 … sub5stringsub1–sub5: суб-ID клика.
utm_source … utm_contentstringutm_source–utm_content: UTM-метки клика.
gclid, fbclid, ttclid, msclkid, wbraidstringgclid, fbclid, ttclid, msclkid, wbraid: ID кликов рекламных платформ в посадочном URL.
refererstringСтраница, с которой пришёл посетитель.
flagsstringПочему клик не засчитан, через ;: bot, duplicate, burst, inactive. Пусто для чистого клика.

players.csv.gz: игроки, чья регистрация поступила в этот день.

ПолеТипЗначение
player_idstringВаш ID игрока.
registered_atstringВремя регистрации, которое вы прислали.
arrived_atstringКогда RevRake её записал.
countrystringДвухбуквенный код страны; пусто, если неизвестна.
attributedbooleantrue, если засчитан партнёру.
attribution_reasonstringПочему — как в ответе на постбэк: click, btag_only, promo_code, no_tag…
affiliate_numberintegerНомер партнёра.
link_numberintegerНомер ссылки.
btagstring<affiliate_number>_<link_number>.
click_idstringКлик, по которому засчитан игрок; пусто, если его нет.
policy_versionintegerВерсия политики атрибуции, которая это решила.

events.csv.gz: все принятые события бренда, поступившие за день, включая дневные сводки SALES, с их содержимым.

ПолеТипЗначение
event_idstringID события в RevRake.
typestringregistration, deposit, chargeback, daily_sales или ngr; для комиссии — cpa, revshare, tier, adjustment или reversal.
external_idstringКлюч события: ID игрока, ID транзакции или игрок и период.
player_idstringВаш ID игрока.
occurred_atstringКогда это произошло, по вашим данным; у комиссии — когда заработана.
received_atstringКогда RevRake принял событие.
sourcestrings2s (API) или file (ежедневный файл).
payloadJSONСобытие, как RevRake его прочитал, JSON.
resultJSONЧто ответил RevRake, JSON.

commissions.csv.gz: строки комиссий, записанные в этот день.

ПолеТипЗначение
commission_idstringID строки, id в GET /v1/commissions.
created_atstringКогда строка записана.
occurred_atstringКогда это произошло, по вашим данным; у комиссии — когда заработана.
typestringregistration, deposit, chargeback, daily_sales или ngr; для комиссии — cpa, revshare, tier, adjustment или reversal.
statusstringhold, approved, paid или rejected на момент выгрузки.
status_reasonstringПочему удержана или отклонена; иначе пусто.
affiliate_numberintegerНомер партнёра.
player_idstringВаш ID игрока.
dealstringНазвание сделки.
deal_versionintegerВерсия сделки, по которой рассчитано.
grossdecimalДепозит или чистый доход, на котором она основана.
gross_currencystringЕго валюта.
amountdecimalКомиссия.
currencystringВалюта сделки.
reporting_amountdecimalКомиссия в валюте отчётов; пусто, пока нет курса.
reporting_currencystringВалюта отчётов рабочего пространства.
reverses_idstringУ сторно — строка, которую оно отменяет.
payout_item_idstringСтрока выплаты, в которую она вошла после закрытия месяца.

Идемпотентность

У каждого события есть естественный ключ. Идентичный повтор возвращает сохранённый ответ с "status":"duplicate". Ответ депозита, ожидавшего регистрации, обновляется при её поступлении. Изменённые денежные данные могут вызвать конфликт; корректировки NGR используют ревизии. После тайм-аута повторите запрос с новой временной меткой подписи.

СобытиеКлючТот же ключ повторно
registrationplayer_idПервый ответ. Атрибуция не решается заново, даже если метки другие.
deposittxn_idСохранённый ответ, обновлённый после поступления ожидаемой регистрации. Изменение игрока, суммы или валюты вызывает конфликт. Покрывающая сводка SALES не удаляет ID транзакции.
chargebacktxn_idПервый ответ. Второй чарджбэк по тому же депозиту под новым txn_id отклоняется.
ngrplayer_id и periodТа же сумма и валюта: первый ответ. Другая сумма: исправление, которое сохраняется как новая редакция, а разница записывается как adjustment.
CSVСтрока REG: player_idКак registration.
CSVДенежная сводка SALES: бренд, игрок и день активностиОдинаковые итоги — повтор. Изменение депозитов, первого депозита, чарджбэков, валюты или границ дня вызывает конфликт, даже для ранее нулевой сводки.
CSVСтрока SALES, доход: игрок и деньКак ngr: изменённая цифра в повторной выгрузке — это исправление.

Статусы и ошибки

Все ответы, которые может дать API, и все статусы, которые может иметь запись, в одном месте. На ошибку возвращается JSON-объект: error (код), message (предложение на английском) и, для invalid, field.

{"error":"invalid","field":"amount","message":"amount must be a positive decimal in KES, for example 25.00."}

HTTP-статусы и коды ошибок

СтатусerrorЭндпоинтКогдаЧто делать
200–/v1/*Запрос обработан. Для события: сохранено или уже было сохранено. Для массива событий или файла: прочитан; смотрите на счётчики, часть элементов могла быть отклонена.
400bad_requestPOST /v1/postbackТело начинается как массив, но не является JSON-массивом событий.Исправьте запрос. Тот же запрос повторно получит тот же ответ.
401unknown_key/v1/*Ключ в X-RevRake-Key неизвестен или отозван, либо это ключ партнёра на эндпоинте записи.Используйте действующий ключ. Повторная отправка не поможет.
401bad_timestamp/v1/*X-RevRake-Timestamp отсутствует, не является целым числом секунд или отличается больше чем на пять минут.Проверьте часы и код подписи, затем отправьте снова со свежей меткой времени.
401bad_signature/v1/*Подпись не соответствует метке времени и телу (для чтения: пути и строке запроса).Проверьте часы и код подписи, затем отправьте снова со свежей меткой времени.
403affiliate_inactiveGET /v1/*Чтение с ключом партнёра, который не одобрен в программе: на рассмотрении, отклонён или приостановлен.В запросе исправлять нечего: аккаунт должен одобрить оператор.
404unknown_affiliateGET /v1/*Чтение с ключом оператора: нет партнёра с номером, указанным в affiliate.Исправьте запрос. Тот же запрос повторно получит тот же ответ.
405–/v1/*Эндпоинт не принимает этот метод. Без JSON-тела.Исправьте запрос. Тот же запрос повторно получит тот же ответ.
413too_largePOST /v1/*Тело больше лимита эндпоинта.Исправьте запрос. Тот же запрос повторно получит тот же ответ.
422invalidPOST /v1/*, GET /v1/reportsСобытие или файл нельзя использовать в таком виде.Исправьте запрос. Тот же запрос повторно получит тот же ответ.
429rate_limitedGET /v1/*Больше чтений, чем позволяет запас ключа. В ответе есть Retry-After.Подождите столько секунд, сколько указано в Retry-After, затем отправьте снова.
500internal/v1/*Что-то пошло не так на нашей стороне.Отправьте снова.
  • Массив без событий или больше чем с 1000 событий отклоняется с 422 invalid без field.
  • Ответ 401 из-за неверной метки времени или подписи с ключом оператора отображается в журнале входящих как bad_signature. Запрос с неизвестным ключом или с ключом партнёра в журнал не попадает.
  • Чтение отвечает 422 только на период отчёта, который нельзя использовать (from и to). Любой другой параметр с недопустимым значением игнорируется, и берётся значение по умолчанию. Проверяйте by, page и per_page в ответе.
  • Повторяйте запрос при таймауте, при 429 и при 500. Не повторяйте другие 4xx без изменений.

На что указывает field в ответе 422

fieldКогда
bodyТело — не корректный JSON или содержит неизвестное либо неверно оформленное поле (например, ts не в формате RFC 3339).
typetype отсутствует или не является одним из четырёх значений.
player_idОтсутствует или длиннее 100 символов; незаполненный плейсхолдер; для ngr — незарегистрированный игрок.
click_idНезаполненный плейсхолдер. Сообщение начинается с misconfigured_macro.
btagНезаполненный плейсхолдер. Сообщение начинается с misconfigured_macro.
promo_codeНезаполненный плейсхолдер. Сообщение начинается с misconfigured_macro.
txn_idОтсутствует или длиннее 200 символов.
ref_txn_idОтсутствует; депозит с таким txn_id неизвестен; или по депозиту уже прошёл чарджбэк.
amountНе десятичное число, допустимое для валюты; для депозита — не больше нуля.
currencyНе трёхбуквенный код.
ggrДля ngr: не десятичная сумма в этой валюте.
bonusesДля ngr: не десятичная сумма в этой валюте.
feesДля ngr: не десятичная сумма в этой валюте.
taxesДля ngr: не десятичная сумма в этой валюте.
tsБольше чем на сутки в будущем.
periodНе день и не месяц, или в будущем.
fromДля GET /v1/reports: from или to не в формате YYYY-MM-DD, from позже to или между ними больше 366 дней.
fileДля /v1/files: файл пуст, не является CSV, не является ни файлом REG, ни файлом SALES, в нём нет обязательного столбца или больше 200 000 строк.
chargebackВ файле SALES: значение ячейки chargeback нельзя применить. Причина указана в сообщении.

Статус события

В ответе на одно событие и для каждого события в results при пакетной отправке.

statusЗначение
acceptedСохранено сейчас. В ответе указано, что оно изменило.
duplicateУже сохранено с тем же ключом; идентичный повтор ничего не меняет. Сопоставление первого депозита между каналами для старых данных также может вернуть duplicate_of. Текущие сводки SALES сохраняют реальные транзакции постбэков и учитывают покрытые дневные суммы один раз.
rejectedТолько при пакетной отправке: событие отклонено, с field и message. На отклонённое одиночное событие возвращается 422.

Что событие изменило в реестре

commission.effectЗначение
createdСоздана строка комиссии: CPA, RevShare или корректировка по исправленной цифре.
cancelledЧарджбэк отклонил комиссию, которая была ещё в холде.
reversedЧарджбэк добавил строку отмены к уже одобренной или выплаченной комиссии.
noneСтрока не создана. Причина указана в reason.

Типы комиссий

typeЗначение
cpaОдна на игрока, когда минимум сделки достигнут первым депозитом или суммой депозитов за вычетом чарджбэков, согласно базе CPA.
revshareДоля чистого игрового дохода (NGR) игрока за период. Отрицательная за период, в котором игрок выиграл.
adjustmentРазница, которую даёт исправленная цифра дохода.
reversalКомиссия с обратным знаком, отозванная после одобрения или выплаты: чарджбэком или оператором с указанием причины. Одобряется сразу и вычитается из следующей выплаты.
tierДоплата по ступени сделки: когда партнёр приводит достаточно новых игроков с депозитом за календарный месяц, разница между ставкой ступени и базовой ставкой добавляется рядом с каждой комиссией этого месяца. Она ждёт в том же холде, что и её комиссия, или сразу одобряется, если та уже одобрена. Отрицательная, когда снимает прежнюю доплату после того, как её комиссию отклонили или отменили.

Статусы комиссий

Строка записывается один раз, и её суммы никогда не меняются. Меняется её статус:

statusЗначение
holdОжидает: окончания холда сделки или того, на что указывает status_reason.
approvedХолд закончился, и строку ничто не удерживает. Она попадёт в следующий ежемесячный пакет выплат. Отмены и некоторые корректировки одобрены с самого начала.
paidПозиция выплаты, в которую входит строка, отмечена как выплаченная.
rejectedВыплачена не будет. Причина указана в status_reason, а в status_note есть комментарий оператора, если он его оставил.

Значения status_reason

Пусто, если строка ожидает только окончания холда, и обычно для одобренных или выплаченных комиссий. Отсутствующий курс чарджбэка может блокировать и одобренную строку. Холд по подозрению в мошенничестве ожидает оператора или настроенного срока истечения флага.

status_reasonПри статусеЗначение
fx_rate_missingholdОтсутствует нужный обменный курс. Расчёт ожидает курс; дневные потоки SALES используют дату активности, отдельные постбэки — свой день UTC.
chargeback_fx_missinghold, approved, paidЧарджбэк пока нельзя оценить. CPA и его доплаты по уровням нельзя включить в новую выплату или отметить выплаченными в существующей до получения курса и завершения сверки.
chargeback_reference_missingholdСводка, полученная до регистрации, содержит агрегированный чарджбэк без указания отменённого депозита для CPA по первому депозиту. Регистрация и сводка сохраняются; созданный CPA ожидает в холде проверки ссылки на транзакцию.
self_referralholdОткрытый фрод-флаг: игрок похож на самого партнёра. Ждёт, пока оператор снимет или подтвердит флаг.
click_velocityholdОткрытый фрод-флаг или клик, вошедший во всплеск: за минуту по одной ссылке с одного адреса больше кликов, чем допускает бренд. Ждёт решения оператора.
duplicate_conversionholdОткрытый фрод-флаг: по игроку передан второй «первый» депозит. Ждёт решения оператора.
paid_trafficholdОткрытый фрод-флаг: клик, который привёл игрока, нёс click ID рекламной сети. Ждёт решения оператора.
disposable_emailholdОткрытый фрод-флаг: игрок зарегистрировался с одноразовым почтовым доменом. Ждёт решения оператора.
geo_mismatchholdОткрытый фрод-флаг: игрок зарегистрировался не в той стране, из которой кликнул. Ждёт решения оператора.
fast_registrationholdОткрытый фрод-флаг: игрок зарегистрировался в течение заданного числа секунд после клика. Ждёт решения оператора.
affiliate_pendingholdПартнёр ещё не был одобрен, когда комиссия была начислена. Когда партнёр одобрен, строка ждёт только окончания обычного холда.
affiliate_rejectedholdЗаявка партнёра отклонена.
affiliate_suspendedholdПартнёр был приостановлен, когда комиссия была начислена. Когда партнёр восстановлен, строка ждёт только окончания обычного холда.
chargebackrejected, approvedУ отклонённой строки: чарджбэк отменил её в холде. У строки отмены: она отменяет комиссию после чарджбэка.
below_thresholdrejectedПосле получения курсов зачётный первый депозит или накопительная сумма за вычетом чарджбэков оказались ниже минимума сделки.
fraudrejected, approvedОператор подтвердил фрод-флаг, который удерживал строку, или отозвал комиссию из-за фрода.
base_rejectedrejectedДоплата по ступени, комиссию которой отклонили, пока обе были в холде.
self_excludedrejected, approvedОператор отозвал комиссию: игрок самоисключился. В отклонённой строке комиссия ещё не была в выплате; в строке отмены уже была.
duplicate_accountrejected, approvedОператор отозвал комиссию: у игрока есть другой аккаунт.
bonus_abuserejected, approvedОператор отозвал комиссию из-за бонус-абьюза.
terms_breachrejected, approvedОператор отозвал комиссию из-за нарушения условий программы.
test_accountrejected, approvedОператор отозвал комиссию: игрок был тестовым аккаунтом.
otherrejected, approvedОператор отозвал комиссию по другой причине, указанной в status_note.

Статусы выплат

Месяц закрывается в пакет выплат с одной позицией на партнёра и валюту. С пакетами и позициями работают в портале; API показывает их результат как статус paid строк комиссий.

Статус пакетаЗначение
draftМесяц закрыт. Оператор проверяет позиции.
approvedЗафиксирован. Если включены счета, каждая позиция к выплате получает номер счёта. Можно скачать файл для банка (CSV) и выплатить позиции.
paidВсе позиции к выплате отмечены как выплаченные.
Статус позицииЗначение
payableБудет выплачена в этом пакете.
carriedМеньше минимальной выплаты или не больше нуля: переносится в следующий пакет.
heldУ партнёра есть открытый фрод-флаг, или программа удерживает выплаты до проверки личности, а проверка ещё не записана. Портал показывает причину. Оператор может снять удержание с позиции, а запись проверки личности снимает его.
no_detailsПартнёр не указал реквизиты для выплаты. В файл для банка не входит.
written_offМесяц закончился ниже нуля, а сделка партнёра не переносит месяцы в минусе: остаток списывается при закрытии, и в следующий пакет ничего не переносится. При лимите позиция получает статус carried и записывает часть сверх лимита как списанную.
paidОтмечена как выплаченная. Её строки комиссий получают статус paid, а трекеру партнёра отправляется постбэк.

Почему строка файла отклоняется

Отклонённая строка учитывается в rejected, перечисляется в problems в виде line N: reason и сохраняется в журнале входящих вместе с самой строкой. Помимо причин, по которым может быть отклонено событие:

  • Строка не является корректным CSV.
  • REG: registration_date или player_id отсутствует либо не читается.
  • SALES: activitydate или player_id отсутствует либо не читается.
  • SALES, выручка: игрок не зарегистрирован.
  • SALES, деньги: сумма отрицательна, не читается или содержит слишком много знаков после запятой для валюты.
  • SALES: первый депозит превышает общую сумму депозитов.
  • SALES: принятый день повторно выгружен с изменёнными денежными итогами, валютой или часовыми границами.
  • SALES: известные отдельные депозиты или чарджбэки превышают дневную сводку.
  • SALES: данные о первом депозите противоречат другому дню или известной транзакции.
  • SALES: агрегированный чарджбэк неоднозначен для CPA по первому депозиту уже зарегистрированного игрока.

Результаты в журнале входящих

СтатусЗначение
acceptedСохранено, с результатом.
duplicateУже сохранено; возвращён первый ответ.
rejectedОтклонено; в деталях указано, какое поле и почему.
bad_signatureНеверная метка времени или подпись.
testТестовое событие со страницы «Интеграция». Проходит настоящий путь и ничего не сохраняет.

Состояния доставки постбэка

СтатусЗначение
queuedЖдёт первой попытки или следующего повтора. В портале показывается как «ожидание» или «повтор».
deliveredТрекер ответил статусом 2xx.
deadВсе повторы не удались. В портале показывается как «остановлено»; партнёр может отправить её вручную.

Статусы партнёра

СтатусЗначение
pendingПодал заявку; оператор ещё не принял решение.
approvedАктивен в программе.
rejectedЗаявка отклонена.
suspendedПриостановлен оператором.

Трекинговая ссылка

Трекинговую ссылку открывает посетитель, ваша платформа её не вызывает. Она сохраняет клик и отвечает редиректом 302 на лендинг бренда. Пока бренд не подтвердил свой сайт, посетитель сначала видит короткую страницу о том, куда ведёт ссылка. Хост назначения берётся из настроек бренда; ссылка может выбрать только путь на нём.

GET https://track.revrake.com/c/a8Kq2Zx?sub1=TRACKER_CLICK_ID&utm_source=telegram
HTTP/1.1 302 Found
Location: https://your-site.example/landing?btag=1001_1&cid=01K6QF3M8Z5T7W9XB2C4D6E8GH&utm_source=telegram
Cache-Control: no-store

Параметры ссылки

ПараметрЗначение
sub1 … sub5Собственные значения партнёра: сохраняются с кликом и возвращаются в постбэках. Значение в адресе заменяет заданное для ссылки.
utm_source utm_medium utm_campaign utm_term utm_contentСохраняются с кликом и передаются на лендинг. Значение в адресе заменяет заданное для ссылки.
gclid fbclid ttclid msclkid wbraidClick ID рекламных сетей. Сохраняются с кликом; доступны как макросы постбэка. Дальше не передаются.

Параметры, добавляемые к URL лендинга

ПараметрЗначение
cidClick ID: 26 символов Crockford base32 (цифры и заглавные буквы без I, L, O, U). Сортируется по времени. Храните его как текст.
btag<номер партнёра>_<номер ссылки>: от одной до девяти цифр, подчёркивание, от одной до девяти цифр.
utm_source … utm_contentUTM-метки клика, если они не пусты.
  • Если URL лендинга бренда содержит {click_id} в строке запроса, click ID подставляется туда, а cid не добавляется.
  • Клик по ссылке неодобренного партнёра сохраняется и помечается, а посетитель попадает на лендинг без cid и btag: такой клик нельзя атрибутировать.
  • Боты, превью ссылок, запросы HEAD, запросы без user agent и повторные клики в течение часа сохраняются и помечаются, а не отбрасываются. В отчёты они не входят.
  • Другие параметры ссылки не сохраняются и не передаются.
  • Ссылка, которой партнёр дал короткое имя, отвечает и по адресу /go/<name>, точно так же, как по /c/<code>. Бренд с собственным подтверждённым трекинговым доменом обслуживает оба пути и на этом домене.
  • На неизвестный код возвращается 404 и HTML-страница ошибки; так же отвечает ссылка, у бренда которой ещё не задан адрес назначения.

Постбэки в трекеры партнёров

Эта часть не требует работы со стороны оператора. Каждый партнёр добавляет в своём портале до 10 адресов назначения: шаблон адреса с макросами и события, о которых нужно сообщать. Когда по игроку партнёра записано событие, RevRake заполняет шаблон и вызывает его запросом GET.

События

Событие{status}Когда
registrationleadИгрок атрибутирован партнёру.
ftdsaleПервый депозит принёс партнёру CPA-комиссию.
commission_approvedapprovedКомиссия одобрена по окончании холда.
commission_rejectedrejectedКомиссия в холде отклонена после проверки.
commission_paidpaidКомиссия выплачена в пакете выплат.
chargebackrejectedЧарджбэк снял комиссию.

Слова-статусы по пресетам

Адрес назначения, созданный из пресета, отправляет в {status} слова, которые знает его трекер. Пресеты Voluum, PeerClick и FunnelFlux Pro, а также «Другой / свой», отправляют слова из таблицы выше. Слова определяются пресетом, который записан у адреса назначения; его сохранённый адрес никогда не меняется.

СобытиеKeitaroBinomRedTrackBeMob
registrationleadleadothernew
ftdsalesalependingapproved
commission_approvedsalesaleapprovedapproved
commission_rejectedrejectedrejectdeclineddeclined
commission_paidsalesaleapprovedapproved
chargebackrejectedrejectdeclinedchargeback

Макросы

Макрос — это имя в фигурных скобках. Он заменяется своим значением в URL-кодировке. Имена сопоставляются без учёта регистра. Неизвестное RevRake имя отправляется как есть, так что опечатка видна в журнале доставок. Неизвестное значение остаётся пустым.

МакросЗначение
{click_id}Click ID RevRake (cid в URL лендинга). Пусто, если игрок атрибутирован только по btag.
{sub1} … {sub5}sub1–sub5 клика. В sub1 обычно передаётся click ID трекера партнёра.
{event}Имя события, как в таблице выше.
{status}Слово, которым трекеры называют это событие, как в таблице выше, либо собственное слово трекера у адреса назначения, созданного из пресета (см. следующую таблицу).
{event_id}Свой для каждого события и не меняется при повторах.
{conversion_id}Один и тот же для всех событий об одной комиссии: ftd, commission_approved, commission_rejected, commission_paid и chargeback. У регистрации он свой. Используйте его как ID транзакции в трекере, который обновляет конверсию, пришедшую повторно под тем же ID, чтобы доход был посчитан один раз.
{player_id} {affiliate_id} {brand_id} {link_id}ID игрока у оператора, номер партнёра, программа и номер ссылки.
{campaign}Название кампании ссылки.
{commission} {commission_minor}Комиссия десятичным числом (40.00) или в минимальных единицах (4000). Пусто для регистрации, 0 для отклонённой комиссии, отрицательная для чарджбэка.
{amount} {amount_minor}Депозит или доход, с которого начислена комиссия, десятичным числом или в минимальных единицах, в валюте, в которой он был сделан. Пусто для регистрации.
{amount_currency}Код ISO валюты депозита. Пусто для регистрации.
{commission_currency}Код ISO валюты комиссии: валюты сделки. Пусто для регистрации.
{currency}Код ISO валюты денег, о которых сообщает постбэк: валюта комиссии, если комиссия есть, иначе валюта депозита, иначе валюта отчётности рабочего пространства.
{occurred_at} {occurred_at_unix}Когда произошло, в формате RFC 3339 или в Unix-секундах.
{country} {device} {os} {browser} {referer}Что известно о клике: страна, тип устройства, операционная система, браузер, реферер.
{utm_source} {utm_medium} {utm_campaign} {utm_term} {utm_content}UTM-метки клика.
{gclid} {fbclid} {ttclid} {msclkid} {wbraid}Click ID рекламных сетей, если клик их содержал.

Другие имена тех же макросов

Трекеры называют одно и то же по-разному. Эти имена тоже принимаются:

{subid}= {sub1}
{clickid}= {click_id}
{payout}= {commission}
{txid}= {event_id}
{transaction_id}= {event_id}

Пресеты

В портале партнёра есть эти шаблоны. Партнёр заменяет хост на хост своего трекера. Каждый шаблон следует документации своего трекера: {conversion_id} стоит в параметре транзакции там, где трекер обновляет конверсию, пришедшую повторно под тем же ID, а {event_id} — там, где трекер отбросил бы более поздние события.

Keitarohttps://YOUR-TRACKER-DOMAIN/POSTBACK-KEY/postback?subid={sub1}&status={status}&payout={commission}&currency={currency}&tid={conversion_id}
Binomhttps://YOUR-TRACKER-DOMAIN/click?cnv_id={sub1}&payout={commission}&cnv_status={status}&cnv_currency={currency}
Voluumhttps://YOUR-TRACKER-DOMAIN/postback?cid={sub1}&payout={commission}&currency={currency}&txid={event_id}&et={event}
RedTrackhttps://YOUR-TRACKER-DOMAIN/postback?clickid={sub1}&sum={commission}&status={status}&type={event}&rdtk_event_id={event_id}
BeMobhttps://YOUR-TRACKER-DOMAIN/postback?cid={sub1}&payout={commission}&txid={conversion_id}&status={status}
PeerClickhttps://YOUR-TRACKER-DOMAIN/postback?cid={sub1}&payout={commission}&txid={conversion_id}&status={status}&currency={currency}
FunnelFlux Prohttps://YOUR-TRACKER-DOMAIN/pb/?hit={sub1}&tx={conversion_id}&rev={commission}&status={status}

Пример

https://YOUR-TRACKER-DOMAIN/postback?click_id={sub1}&event={event}&status={status}&payout={commission}&currency={currency}&tid={conversion_id}&eid={event_id}
GET https://tracker.example/postback?click_id=TRACKER_CLICK_ID&event=ftd&status=sale&payout=40.00&currency=KES&tid=0199b2c9-0a11-7c3e-9f20-7d4b1e6a2c58&eid=0199b2c9-03aa-7e10-b6d2-91c07f5e2a18%3Aftd

Доставка

  • Постбэк ставится в очередь в той же транзакции, что и событие, о котором он сообщает, и отправляется примерно в течение десяти секунд, сначала самые старые.
  • Запрос — это GET с user agent RevRake-Postback/1. Он следует не более чем по трём редиректам и прекращает ожидание через 5 секунд. Сертификаты проверяются.
  • Ответ 2xx — успех. Всё остальное — неудача; доставка повторяется через 1 минуту, 5 минут, 25 минут, 2 часа, 10 часов и 24 часа.
  • После последнего повтора доставка помечается как остановленная. Партнёр может отправить её вручную.
  • Каждая попытка записывается с длительностью, статусом и первыми 500 символами ответа.
  • После 5 и после 15 неудач подряд владелец адреса назначения получает e-mail. После 20 адрес назначения выключается. Его доставки, включая доставки событий, которые происходят, пока он выключен, продолжают вставать в очередь и отправляются, когда партнёр включает его снова. Адрес назначения, который партнёр выключил сам, ничего нового не получает.
  • RevRake вызывает только публичные адреса. Loopback-адреса, частные, link-local и адреса carrier-grade NAT отклоняются в момент установления соединения, так что редирект не позволяет это обойти.
  • Шаблон должен быть полным адресом http:// или https:// длиной не более 2000 символов.

Почему попытка не удалась

timeoutНет ответа за 5 секунд.
dnsИмя хоста не найдено.
refusedСоединение отклонено.
blocked_addressАдрес частный или локальный.
tlsПроблема с сертификатом.
too_many_redirectsБольше трёх редиректов.
http_errorТрекер ответил статусом, отличным от 2xx.
otherСоединение не удалось по другой причине.

Вебхуки оператора

Вебхуки сообщают собственным системам оператора (CRM, хранилищу данных, чат-каналу), что происходит в программе. Администратор рабочего пространства добавляет эндпоинт на странице «Интеграция» портала оператора: адрес на вашем сервере, события для отправки и необязательное описание. На каждое из этих событий RevRake отправляет на адрес подписанный JSON-запрос POST. Другие участники команды не могут видеть или менять эндпоинты.

Адрес указывается полностью, с https://, на публичном хосте (http:// принимается, но используйте https://). У каждого эндпоинта свой секрет, он начинается с whsec_. Секрет показывается один раз, при создании эндпоинта или смене секрета: скопируйте его сразу. Смена секрета сразу создаёт новый, а старый перестаёт подписывать.

Endpoint может быть и каналом Slack или Microsoft Teams: выберите «Сообщение в Slack» или «Сообщение в Microsoft Teams» и вставьте адрес входящего вебхука канала (для Teams — процесс «Когда получен запрос вебхука Teams»). Тогда каждое событие приходит в канал фразой вместо подписанного JSON, а сумма позволяет оставить только первые депозиты от этого размера.

События

Отметьте одно или несколько для каждого эндпоинта. Поля data описаны ниже; поле, которое не относится к событию, не передаётся.

СобытиеПоля dataКогда
affiliate.appliedaffiliate_number affiliate_name email promotes_on trafficКто-то подал заявку на странице вашей программы или по ссылке-приглашению на сделку. Отправляется в момент подачи заявки, возможно, ещё до того, как заявитель подтвердил email. Партнёр, которого вы добавили и пригласили сами, вместо этого отправляет affiliate.approved.
affiliate.approvedaffiliate_number affiliate_name email reason decided_by invitedВы одобрили партнёра: новую заявку или того, кого ранее отклонили или приостановили. Партнёр, которого вы добавили и пригласили сами, одобряется сразу и отправляет это событие с invited, равным true.
affiliate.rejectedaffiliate_number affiliate_name email reason decided_byВы отклонили заявку.
affiliate.suspendedaffiliate_number affiliate_name email reason decided_byВы приостановили одобренного партнёра.
player.registeredplayer_id occurred_at attributed affiliate_number affiliate_name attribution_reasonИгрок зарегистрирован, подписанным событием или строкой REG-файла, с атрибуцией или без. Один раз на игрока.
commission.createdplayer_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currencyСоздана строка комиссии: CPA по условию первого депозита или накопительной суммы сделки, либо доля выручки или корректировка заявленного чистого дохода. Доплаты по уровням и отмены не отправляют это событие.
commission.approvedplayer_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currencyКомиссия в холде одобрена, потому что закончился период холда, доплаты по уровням тоже. Строка, одобренная сразу, событие не отправляет.
commission.rejectedplayer_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currencyКомиссия в холде отклонена, потому что вы подтвердили флаг фрода, который её держал. commission равна нулю. CPA, отменённая чарджбэком, отправляет вместо этого commission.reversed.
commission.paidplayer_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currencyСтрока комиссии выплачена: одно событие на каждую строку позиции выплаты, отмеченной как выплаченная, включая строки отмены и доплаты по уровням.
commission.reversedplayer_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currencyЧарджбэк забрал CPA: отменил её в холде или добавил строку отмены после одобрения или выплаты. commission_id указывает на CPA, commission равна её сумме со знаком минус, а amount это депозит, по которому прошёл чарджбэк.
payout.batch_closedbatch_id period reference items payable_by_currency closed_by_handМесяц закрыт в черновик пакета выплат, вручную или по расписанию.
payout.batch_approvedbatch_idЧерновик пакета выплат одобрен и заблокирован.
payout.paidbatch_id item_id affiliate_number affiliate_name currency amountПозиция одобренного пакета отмечена как выплаченная. Пакет, все позиции которого выплачены, отдельного события не отправляет.
tracking.health_alertbrand kind since quiet_hours clicks_at_leastСсылки бренда получили не меньше заданного числа кликов за заданные часы, а регистраций не пришло (страница «Интеграция», «Состояние трекинга»). Отправляется один раз; проверка каждый час.
tracking.health_clearedbrand raised_at cleared_atПришла первая регистрация после предупреждения о состоянии трекинга, и предупреждение снято.
flag.raisedkind detail affiliate_number affiliate_nameНа партнёра создана новая пометка о фроде (правилом, повторным первым депозитом или самореферальством). Пометки о всплесках кликов есть только на странице «Пометки».
postback.destination_offdestination failures affiliate_number affiliate_nameНазначение постбэков партнёра отключено после допустимого лестницей повторов числа неудачных доставок подряд.
file.latesource dateЕжедневный файл, забираемый по расписанию, не пришёл через три часа после своего времени. Один раз на файл и день.
webhook.testmessageТолько от кнопки «Отправить тест». Его нельзя отметить, он не повторяется и не попадает в журнал доставок.

Тело запроса

Каждый запрос несёт один JSON-объект:

ПолеТипЗначение
idstringID события, UUID. Одинаков для всех эндпоинтов, получающих событие, и при каждом повторе: используйте его, чтобы отбрасывать повторы.
typestringСобытие, как в таблице выше.
created_atstringКогда событие было поставлено в очередь, в формате RFC 3339 в UTC, с долями секунды.
dataobjectДанные события. См. поля ниже.
{
  "id": "0199b2c9-0a11-7c3e-9f20-7d4b1e6a2c58",
  "type": "commission.created",
  "created_at": "2026-10-05T09:12:44.318204Z",
  "data": {
    "player_id": "PLR-1001",
    "occurred_at": "2026-10-05T09:12:40Z",
    "attributed": true,
    "affiliate_number": 1001,
    "affiliate_name": "Odds Garage",
    "commission_id": "0199b2c9-0a0f-7a51-8c3d-5e2f4a6b7c90",
    "commission_type": "cpa",
    "amount": "25.00",
    "amount_currency": "USD",
    "commission": "40.00",
    "commission_currency": "USD"
  }
}

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

Заголовки

ЗаголовокЗначение
RevRake-EventСобытие, то же, что type в теле.
RevRake-DeliveryID этой доставки на этот эндпоинт, UUID. Одинаков при каждом повторе и при повторной отправке вручную.
RevRake-TimestampКогда отправлена эта попытка, в секундах Unix. Новая при каждой попытке.
RevRake-SignatureHMAC-SHA256 в нижнем регистре hex, под секретом эндпоинта, от <timestamp>.<raw body>. Новая при каждой попытке.

Запрос также несёт Content-Type: application/json и user agent RevRake-Webhook/1.

POST /revrake-webhook HTTP/1.1
Host: example.com
Content-Type: application/json
User-Agent: RevRake-Webhook/1
RevRake-Event: commission.created
RevRake-Delivery: 0199b2c9-0b7e-7d02-8a41-3c5e6f708192
RevRake-Timestamp: 1791191571
RevRake-Signature: <hex HMAC-SHA256 of "1791191571.<raw body>">

Поля data

ПолеТипЗначение
affiliate_numberintegerНомер партнёра.
affiliate_namestringИмя партнёра.
emailstringEmail, с которым партнёр входит в портал.
promotes_onstringЧто заявитель написал о том, где он продвигает.
trafficarray of stringИсточники трафика, отмеченные заявителем: seo, telegram, paid_social, youtube, email или offline.
reasonstringПричина, сообщённая партнёру. Всегда есть при отклонении или приостановке; при одобрении может быть пустой.
decided_bystringEmail участника команды, принявшего решение или добавившего партнёра.
invitedbooleantrue, если вы добавили и пригласили партнёра сами, без заявки. В остальных случаях поля нет.
player_idstringВаш ID игрока.
occurred_atstringКогда это произошло, в формате RFC 3339: регистрация, депозит, конец периода дохода или чарджбэк. Для одобрения, отклонения или выплаты: момент изменения.
attributedbooleanПринадлежит ли игрок партнёру. Для комиссии всегда true.
attribution_reasonstringПочему игрок был или не был атрибутирован: одна из причин атрибуции.
commission_idstringID строки комиссии в RevRake: id строки в GET /v1/commissions. Одинаков во всех событиях об этой комиссии.
commission_typestringТип строки комиссии: cpa, revshare, adjustment или tier, а также reversal для строки отмены в commission.paid. В commission.reversed это тип CPA, который был отменён.
amountstringДля комиссии: депозит или NGR, от которого она посчитана, десятичным числом, в своей валюте. Для payout.paid: сумма позиции, десятичным числом.
amount_currencystringISO-код валюты amount.
commissionstringКомиссия десятичным числом в валюте сделки (40.00). Отрицательная для отмены, корректировки в меньшую сторону и периода, в котором игрок выиграл.
commission_currencystringISO-код валюты комиссии: валюты сделки.
batch_idstringID пакета выплат в RevRake, UUID.
periodstringМесяц, который закрывает пакет, YYYY-MM.
referencestringРеференс пакета, тот же, что в файле для банка, например po_2026-09_demo.
itemsintegerСколько позиций в пакете, независимо от их статуса.
payable_by_currencyobjectПо каждой валюте сумма всех позиций, десятичным числом (1250.00), независимо от статуса, включая перенесённые.
closed_by_handbooleantrue, если месяц закрыл человек, false при закрытии по расписанию.
item_idstringID позиции выплаты в RevRake, UUID.
currencystringВалюта позиции.
messagestringФраза о том, что тест дошёл.

Проверка запроса

  1. Прочитайте сырое тело как байты, до любого разбора JSON.
  2. Убедитесь, что RevRake-Timestamp отличается от ваших часов не более чем на 5 минут, иначе отклоните запрос: так записанный запрос нельзя будет воспроизвести позже.
  3. Вычислите hex HMAC-SHA256 от метки времени, точки и сырого тела под секретом эндпоинта и сравните с RevRake-Signature за постоянное время.
  4. Только после этого разберите тело. Если вы уже обработали его id, ответьте 2xx и ничего не делайте.
  5. Отвечайте любым 2xx в течение 5 секунд, а медленную работу выполняйте после.

Та же проверка на Node.js и Python, как её показывает страница «Интеграция»:

Node.js
const crypto = require("node:crypto");

// raw: the body exactly as received (a Buffer), before parsing it as JSON.
function verify(raw, headers, secret) {
  const ts = headers["revrake-timestamp"] ?? "";
  if (!/^\d+$/.test(ts) || Math.abs(Date.now() / 1000 - Number(ts)) > 300) return false;
  const expected = crypto.createHmac("sha256", secret).update(ts + ".").update(raw).digest();
  const got = Buffer.from(headers["revrake-signature"] ?? "", "hex");
  return got.length === expected.length && crypto.timingSafeEqual(got, expected);
}
Python
import hashlib, hmac, time

# raw: the body exactly as received (bytes), before parsing it as JSON.
def verify(raw: bytes, headers, secret: str) -> bool:
    ts = headers.get("RevRake-Timestamp", "")
    if not ts.isdigit() or abs(time.time() - int(ts)) > 300:
        return False
    expected = hmac.new(secret.encode(), ts.encode() + b"." + raw, hashlib.sha256).hexdigest()
    return hmac.compare_digest(expected, headers.get("RevRake-Signature", ""))

Доставка, повторы и отключение

  • Доставка ставится в очередь в той же транзакции, что и изменение, о котором она сообщает, поэтому событие отправляется тогда и только тогда, когда изменение сохранено. Оно отправляется примерно в течение десяти секунд, начиная с самых старых.
  • Доставка выполняется как минимум один раз: одно событие может прийти больше одного раза, например, если ваш ответ потерялся по дороге. Отбрасывайте повторы по id из тела.
  • Порядок не гарантирован: повтор может прийти после более позднего события. Упорядочивайте события по created_at или occurred_at, а не по времени прихода.
  • Ответ 2xx в течение 5 секунд считается успехом. Всё остальное считается неудачей и повторяется через 1 минуту, 5 минут, 25 минут, 2 часа, 10 часов и 24 часа, с тем же телом и новыми меткой времени и подписью.
  • После последнего повтора доставка помечается как остановленная. Администратор может отправить её снова кнопкой «Отправить снова» в журнале доставок; тогда она снова проходит всё расписание повторов.
  • После 20 неудачных попыток подряд эндпоинт отключается. Его события продолжают вставать в очередь, и всё накопленное отправляется, когда администратор включит его снова. Email при этом не отправляется: состояние каждого эндпоинта видно на странице «Интеграция».
  • Эндпоинт, который вы отключили сами, ничего нового не получает: пока он выключен, события для него в очередь не ставятся.
  • RevRake обращается только к публичным адресам: ждёт ответа не дольше 5 секунд и проверяет сертификаты. Loopback, частные, link-local адреса и адреса carrier-grade NAT отклоняются. Редиректу RevRake не следует: ответ 3xx считается неудачей с ошибкой redirect, а журнал доставок показывает адрес, на который он указывал.

Проверьте и читайте журнал доставок

  • Нажмите «Отправить тест» у эндпоинта: событие webhook.test отправляется сразу, подписанное как настоящее, и вы видите статус, которым ответил эндпоинт, и время ответа. Тест не повторяется, не попадает в журнал доставок и не считается неудачей.
  • Журнал доставок эндпоинта показывает последние 100 доставок: событие, состояние (ожидание, повтор, остановлено или доставлено), число попыток, последний статус или ошибку, первые 500 символов вашего ответа, следующую попытку и тело в том виде, в каком оно было отправлено.
  • Неудачная попытка описывается теми же словами, что и для постбэка (см. почему попытка не удалась), плюс redirect: ваш эндпоинт ответил кодом 3xx. Состояния те же, что у доставки постбэка.
{
  "id": "0199b2d4-5c60-7b1a-9e3f-1a2b3c4d5e6f",
  "type": "webhook.test",
  "created_at": "2026-10-05T09:30:02.104377Z",
  "data": {
    "message": "A test from RevRake. If you can read this, your endpoint works."
  }
}

Рекомендации

  • Храните секрет на своём сервере, никогда на странице или в приложении. Если он утёк, смените его и сразу переведите эндпоинт на новый: старый секрет перестаёт работать немедленно.
  • На запрос, подпись которого не совпала, отвечайте 4xx. Он будет повторён с подписью текущим секретом, поэтому доставка, пришедшая во время смены секрета, не потеряется.
  • Сохраняйте id каждого обработанного события и игнорируйте событие, которое уже видели.
  • Сначала ответьте, потом работайте: поставьте событие в собственную очередь и ответьте 2xx, чтобы медленная база данных никогда не заставляла RevRake повторять запрос.
  • Указывайте конечный адрес эндпоинта. Редиректу RevRake не следует: попытка завершается ошибкой redirect, а журнал доставок называет адрес, который нужно указать вместо него.
  • Используйте commission_id, чтобы связывать события об одной комиссии, и сверяйтесь с GET /v1/commissions: ночное чтение за последние 60 дней поймает всё пропущенное.
  • Отмечайте только те события, которые используете. Каждое из них это запрос к вашему серверу.

Файл OpenAPI

Четыре подписанных эндпоинта, со всеми статусами и причинами в виде перечислений, описаны в openapi.yaml (OpenAPI 3.1) — для генераторов кода и API-клиентов. Его адрес не меняется.

Готовы подключаться? Создайте программу и получите ключ.

Вы создаёте программу сами: зарегистрируйтесь, подтвердите e-mail — и через несколько минут вы внутри. Бесплатно для операторов, навсегда. Без карты.

Вопросы? Пишите на hello@revrake.com