L'API RevRake.
Tout ce que la plateforme d'un opérateur envoie à RevRake, ce qui revient, et ce que RevRake envoie aux trackers des affiliés et aux propres systèmes de l'opérateur. Pour l'ordre dans lequel procéder, lisez le guide d'intégration.
URL de base
L'API se compose de quatre endpoints signés pour la plateforme de l'opérateur, deux pour écrire et deux pour lire, et du lien de tracking qu'ouvrent les visiteurs. Les endpoints signés sont aussi publiés sous forme de fichier OpenAPI 3.1.
| Endpoint | Signification |
|---|---|
POST https://app.revrake.com/v1/postback | Déclare un événement, ou un lot d'événements. Signé. |
POST https://app.revrake.com/v1/files | Envoie un fichier quotidien REG ou SALES. Signé. |
GET https://app.revrake.com/v1/reports | Lit un rapport, en JSON ou en CSV. Signé, avec une clé opérateur ou une clé affilié. |
GET https://app.revrake.com/v1/commissions | Lit le grand livre des commissions, page par page. Signé, avec une clé opérateur ou une clé affilié. |
GET https://app.revrake.com/v1/affiliates | Liste les affiliés de la marque. Signé, avec la clé de l'opérateur. |
GET https://app.revrake.com/v1/links | Liste les liens de suivi. Signé, avec une clé d'opérateur ou d'affilié. |
GET https://app.revrake.com/v1/deals | Liste les accords avec les conditions en vigueur. Signé, avec la clé de l'opérateur. |
GET https://track.revrake.com/c/{code} | Le lien de tracking : enregistre le clic et redirige. Non signé. |
Les portails sur app.revrake.com utilisent leurs propres endpoints derrière une session connectée. Ce n'est pas une API publique, et ils peuvent changer sans préavis. Les rapports, le grand livre et les lignes de paiement peuvent aussi y être téléchargés en CSV.
Clés
Il existe deux sortes de clé. Chacune a un identifiant de clé et un secret, et chacune signe les requêtes de la même façon. Les clés ne se partagent jamais : chaque partie a la sienne.
| L'identifiant de clé commence par | À qui elle appartient | Ce qu'elle peut faire |
|---|---|---|
pb_ | L'opérateur. Une clé active par marque, sur la page Intégration du portail opérateur. Un admin de l'espace de travail peut voir le secret et renouveler la clé. | Envoie des événements et des fichiers. Lit les rapports et le grand livre de tout le programme, ou d'un seul affilié avec affiliate=<number>. |
ak_ | Un affilié. Chaque affilié crée la sienne dans l'onglet API de son portail affilié. Le secret est affiché une seule fois, à la création de la clé. | Lit les rapports et les commissions de cet affilié, et rien d'autre. Elle ne peut pas envoyer d'événements : /v1/postback et /v1/files répondent 401 unknown_key. |
Ne donnez jamais la clé opérateur à un affilié. Elle lit les chiffres de tous les affiliés et peut écrire des événements. Un affilié qui veut un accès par API crée sa propre clé.
- Une nouvelle clé révoque l'ancienne immédiatement, pour les deux sortes. Un affilié peut aussi révoquer sa clé et n'en avoir aucune.
- Une clé affilié ne fonctionne que tant que l'affilié est approuvé dans le programme. Sinon, une lecture répond
403affiliate_inactive. - Avec une clé affilié, le paramètre
affiliateest ignoré etby=affiliateest traité par jour. - La limite de débit des lectures est comptée par clé.
Authentification
Chaque requête /v1 est signée avec une clé. Chaque requête porte trois en-têtes :
| En-tête | Valeur |
|---|---|
X-RevRake-Key | Votre identifiant de clé. Il commence par pb_ (opérateur) ou ak_ (affilié). |
X-RevRake-Timestamp | L'heure Unix actuelle en secondes. Une requête est acceptée à cinq minutes près, avant ou après. |
X-RevRake-Signature | Le HMAC-SHA256 en hexadécimal minuscule, avec votre secret, de <timestamp>.<body> pour un POST et de <timestamp>.<path>?<query> pour un GET. |
Pour signer une requête :
- Construisez le corps et gardez les octets exacts que vous allez envoyer.
- Prenez l'heure Unix actuelle en secondes, en texte décimal.
- Concaténez le timestamp, un point (
.) et le corps. - Calculez le HMAC-SHA256 de ce texte avec votre secret et écrivez-le en hexadécimal minuscule.
- Envoyez le corps inchangé, avec les trois en-têtes.
Signer une lecture
Un GET n'a pas de corps : la signature porte donc sur la cible de la requête, c'est-à-dire le chemin et la query exactement tels qu'ils sont envoyés, par exemple 1790000000./v1/reports?by=link&days=7. Sans query, c'est le timestamp, un point et le chemin. Construisez l'adresse une fois, signez ce texte et envoyez ce texte : un client qui réordonne ou réencode la query après la signature casse la signature.
- La clé est vérifiée d'abord, puis le timestamp, puis la signature.
- L'en-tête
Content-Typen'est pas obligatoire. Envoyezapplication/jsonpour les événements ettext/csvpour les fichiers. - Une clé renouvelée cesse de fonctionner immédiatement.
Exemples de signature
Chaque exemple a une seule fonction de signature, envoie une inscription puis lit un rapport. Remplacez l'identifiant de clé et le secret par les vôtres.
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))
} Vecteur de test
Avec ces entrées, votre code doit produire exactement ces signatures :
- Secret
- test_secret
- Timestamp
- 1791072000
- Corps
- {"type":"registration","player_id":"PLR-1001","btag":"1001_1"}
- Signature
- 115d8c73c6069d8953a36ca3a68c114da6232e4ba31889fd519d41ab1350a603
- Cible de la requête d'une lecture
- /v1/reports?by=link&days=7
- Signature de la lecture
- ed1ed72dd7ddef22c762f63b8919011e7c36c7214b55b72693c5927fb4b911d0
Limites
Voici toutes les limites que le produit applique aujourd'hui aux intégrations, au tracking et aux affiliés, avec leurs valeurs. La connexion, la réinitialisation du mot de passe et les candidatures ont aussi des limites contre les abus.
| Limite | Signification |
|---|---|
| 120 | Lectures par clé et par minute : GET /v1/reports et GET /v1/commissions ensemble |
| 30 000 | Requêtes d'événements par clé et par minute : POST /v1/postback, jusqu'à 1 000 d'un coup |
| 60 | Fichiers par clé et par minute : POST /v1/files, jusqu'à 10 d'un coup |
| 4 MB | Corps de POST /v1/postback, un événement ou un lot |
| 32 MB | Corps de POST /v1/files |
| 1 – 1000 | Événements dans un lot |
| 200 000 | Lignes de données dans un fichier |
| 300 s | Écart entre X-RevRake-Timestamp et l'heure réelle, dans un sens ou dans l'autre |
| 24 h | Jusqu'où ts et period peuvent être dans le futur |
| 100 | Longueur de player_id, en caractères |
| 200 | Longueur de txn_id, en caractères |
| 0 / 2 | Décimales d'un montant : celles de la devise (deux pour la plupart, aucune pour des devises comme XOF, UGX ou JPY) |
| 1 – 365 | days d'un rapport |
| 10, 25, 50, 100, 500, 1000 | per_page du grand livre : l'une de ces valeurs |
| 1 – 100 000 | page du grand livre |
| 100 | Longueur de q, en caractères ; un texte plus long est tronqué |
| 200 | Longueur de sub1 à sub5, de chaque tag UTM et de chaque click ID de régie publicitaire sur un lien de tracking, en caractères ; les valeurs plus longues sont tronquées |
| 10 | Destinations de postback par affilié |
| 2000 | Longueur d'un modèle d'adresse de postback, en caractères |
| 5 s | Temps dont dispose un tracker pour répondre à un postback |
| 50 | Journal des entrées affiché dans le portail : dernières entrées des 7 derniers jours |
| 2000 | Longueur de l'adresse d'un endpoint de webhook, en caractères |
| 5 s | Temps dont dispose un endpoint de webhook pour répondre |
| 20 | Tentatives de webhook échouées d'affilée avant que l'endpoint soit désactivé |
| 100 | Envois par endpoint de webhook affichés dans le journal des envois |
| 2 – 40 | Longueur d'un code promo : lettres, chiffres, traits d'union et tirets bas |
| 32 MB | Taille d'un fichier que RevRake récupère à votre adresse |
| 60 s | Temps dont votre adresse dispose pour livrer un fichier récupéré |
| 0 – 3600 s | Secondes après le clic pour la règle de délai d'inscription (0 la désactive) |
| 0 – 365 | Jours avant qu'une alerte de fraude ouverte se décide seule (0 signifie jamais) |
| 1 – 200 | Alertes levées ou confirmées en une seule décision groupée |
| 0 – 10 000 (20) | Clics par minute sur un lien depuis une même adresse avant que l'alerte de rafale de clics soit levée (0 la désactive ; 20 si vous ne la changez pas) |
| 60 + 1 / min | Liens de tracking qu'un affilié peut créer : 60 d'un coup, puis un par minute. Au-delà, la réponse est 429 avec Retry-After |
| 2 MB | Taille d'une image de bannière téléversée dans le portail : PNG, JPEG, GIF ou WebP |
Les deux endpoints d'écriture, POST /v1/postback et POST /v1/files, sont limités par clé (voir le tableau). Chaque réponse porte X-RateLimit-Limit et X-RateLimit-Remaining ; un refus est un 429 avec Retry-After. Envoyez au rythme de vos événements et utilisez des lots pour un rattrapage. Le lien de tracking n'a pas de limite de débit ; une rafale inhabituelle de clics sur un lien depuis une même adresse lève un signalement de fraude et est tout de même redirigée.
La limite de débit des lectures
- Chaque clé peut faire 120 lectures par minute. Le quota est une réserve de 120 : une lecture en prend une, et une revient toutes les demi-secondes. Une clé restée inactive peut faire 120 lectures d'un coup ; ensuite, deux par seconde.
- Chaque réponse à une lecture porte
X-RateLimit-Limit(toujours120) etX-RateLimit-Remaining(combien de lectures il reste à cet instant). - Au-delà de la limite, la réponse est
429rate_limitedavec un en-têteRetry-After: le nombre de secondes à attendre. Attendez, puis renvoyez la même requête, signée avec un timestamp frais. - La limite est comptée par clé : la clé de l'opérateur et la clé de chaque affilié ont chacune leur quota.
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."} Gérer un 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
Déclare un événement de la plateforme de l'opérateur. Le corps est un objet JSON avec un type et les champs de ce type, ou un tableau JSON de tels objets (un lot).
POST https://app.revrake.com/v1/postback typevautregistration,deposit,chargebackoungr.- Un champ qui n'est pas listé pour le type est refusé avec un
422, de sorte qu'une faute de frappe n'est jamais ignorée en silence. tsest l'heure de l'événement au format RFC 3339 (2026-10-04T08:15:00Z). S'il est omis, l'heure de la requête est utilisée. Il doit porter un décalage UTC (Zou+03:00) ; une heure sans décalage est refusée. Il ne peut pas être à plus d'un jour dans le futur.- Un montant est un décimal, en texte JSON ou en nombre JSON :
"25.00"ou25.5. Pas de séparateur de milliers, pas d'exposant, et pas plus de décimales que la devise n'en a. currencyest un code ISO 4217 à trois lettres. Les minuscules sont acceptées. S'il est omis, la devise de reporting de l'espace de travail est retenue.- Les espaces en début et en fin des valeurs de texte sont retirées, sauf pour
click_idetbtag: envoyez-les exactement tels qu'ils sont arrivés sur la landing page.
registration
Un nouveau joueur. Envoyez click_id, btag, promo_code, ou plusieurs d'entre eux ; sans aucun, le joueur est enregistré comme non attribué. Le joueur est attribué une seule fois, ici. Réponse : attribution.
{"type":"registration","player_id":"PLR-1001","click_id":"01K6QF3M8Z5T7W9XB2C4D6E8GH","btag":"1001_1"} | Champ | Type | Obligatoire | Exemple | Signification |
|---|---|---|---|---|
player_id | string | oui | "PLR-1001" | Votre identifiant du joueur. Jusqu'à 100 caractères. La clé de l'événement. |
click_id | string | non | "01K6QF3M8Z5T7W9XB2C4D6E8GH" | Le cid avec lequel le joueur est arrivé : 26 caractères, lettres et chiffres ; majuscules ou minuscules. |
btag | string | non | "1001_1" | Le btag que votre plateforme a stocké sur le joueur : <numéro d'affilié>_<numéro de lien>, uniquement des chiffres. |
promo_code | string | non | "GARAGE50" | Le code promo que le joueur a saisi à l'inscription. Insensible à la casse. Il n'attribue le joueur que si click_id et btag ne le font pas. |
email_hash | string | non | "9f86d081…0f00a08" | SHA-256 de l'e-mail en minuscules, en hexadécimal. Utilisé uniquement par le contrôle d'auto-parrainage. |
email_domain | string | non | "example.com" | Le domaine de l'e-mail du joueur, la partie après le @ (example.com). Utilisé uniquement par la règle e-mail jetable. N'envoyez que le domaine : si une adresse complète arrive, seul le domaine est gardé sur le joueur, mais le journal des entrées montre toujours la requête telle qu'elle est arrivée. |
ip | string | non | "203.0.113.7" | L'adresse IP à l'inscription. Elle est hachée, et utilisée uniquement par le contrôle d'auto-parrainage et pour trouver le clic correspondant à un btag. |
country | string | non | "KE" | Le pays du joueur : deux lettres, ISO 3166-1 alpha-2 (GB, KE). Les minuscules sont acceptées. Une valeur qui n'a pas deux lettres laisse le joueur sans pays. Sans ce champ, le pays du clic qui a amené le joueur est utilisé. Un deal peut lister des pays pour lesquels il ne paie pas. |
ts | string | non | "2026-10-04T08:15:00Z" | Quand le joueur s'est inscrit. La fenêtre d'attribution est mesurée à partir de là. |
{
"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
Envoyez un événement deposit par dépôt, avec votre identifiant de transaction dans txn_id. Le deal compare son minimum CPA au premier dépôt ou aux dépôts cumulés, déduction faite des chargebacks. La qualification crée une commission CPA par joueur, en rétention.
{"type":"deposit","player_id":"PLR-1001","txn_id":"TX-88213","amount":"25.00","currency":"KES","first":true} | Champ | Type | Obligatoire | Exemple | Signification |
|---|---|---|---|---|
player_id | string | oui | "PLR-1001" | Votre identifiant du joueur. Jusqu'à 100 caractères. |
txn_id | string | oui | "TX-88213" | Votre identifiant de transaction. Jusqu'à 200 caractères. La clé de l'événement. |
amount | string | number | oui | "25.00" | Le dépôt, supérieur à zéro. |
currency | string | non | "KES" | La devise du dépôt. Toute devise est acceptée. |
ts | string | non | "2026-10-04T08:20:00Z" | Quand le dépôt a été fait. Détermine quelle version du deal et quel taux de change du jour s'appliquent. |
first | boolean | non | true | true s'il s'agit du premier dépôt du joueur. S'il est omis, le dépôt compte comme premier si RevRake n'en connaît aucun antérieur pour ce joueur. |
{
"status": "accepted",
"event_type": "deposit",
"event_id": "0199b2c9-03aa-7e10-b6d2-91c07f5e2a18",
"commission": {
"effect": "created",
"type": "cpa",
"amount_minor": 4000,
"status": "hold"
}
} chargeback
Envoyez un événement chargeback avec son propre txn_id et le txn_id du dépôt initial dans ref_txn_id. Il annule ce dépôt en totalité. Pour le CPA cumulé, la commission est reprise seulement si le total admissible restant passe sous le minimum : une commission en rétention est annulée ; une commission approuvée ou payée reçoit une ligne d’annulation.
{"type":"chargeback","txn_id":"CB-5001","ref_txn_id":"TX-88213"} | Champ | Type | Obligatoire | Exemple | Signification |
|---|---|---|---|---|
txn_id | string | oui | "CB-5001" | Votre identifiant du chargeback lui-même. Jusqu'à 200 caractères. La clé de l'événement. |
ref_txn_id | string | oui | "TX-88213" | Le txn_id du dépôt concerné par le chargeback. |
player_id | string | non | "PLR-1001" | Facultatif. Si fourni, doit correspondre au joueur du dépôt référencé. |
ts | string | non | "2026-10-09T11:00:00Z" | Quand le chargeback a eu lieu. |
{
"status": "accepted",
"event_type": "chargeback",
"event_id": "0199cc10-7b2d-7c41-a3f0-5d2e8b9c1f47",
"commission": {
"effect": "cancelled",
"type": "cpa",
"amount_minor": 4000,
"status": "rejected"
}
} ngr
Le revenu net de jeu (NGR) d'un joueur pour un jour ou un mois. Il rapporte le RevShare de la version du deal en vigueur à la fin de la période, en rétention. Le joueur doit être inscrit. Réponse : commission.
{"type":"ngr","player_id":"PLR-1001","period":"2026-10-03","amount":"118.40","currency":"KES"} | Champ | Type | Obligatoire | Exemple | Signification |
|---|---|---|---|---|
player_id | string | oui | "PLR-1001" | Votre identifiant du joueur. Jusqu'à 100 caractères. |
period | string | oui | "2026-10-03" | Le jour (YYYY-MM-DD) ou le mois (YYYY-MM) que couvre le montant. Un mois et son premier jour sont deux périodes différentes. Pas à plus d'un jour dans le futur. |
amount | string | number | oui | "118.40" | Le revenu net de jeu (NGR) de la période. Négatif quand le joueur a gagné. |
currency | string | non | "KES" | La devise du montant. |
ggr | string | number | non | "240.00" | Facultatif. Le revenu brut de jeu de la période, dans la même devise. Montré à l'affilié ; il ne change pas la commission. |
bonuses | string | number | non | "80.00" | Facultatif. Les bonus déduits du revenu brut. Affiché seulement. |
fees | string | number | non | "21.60" | Facultatif. Les frais déduits du revenu brut, comme les frais de paiement ou de plateforme. Affiché seulement. |
taxes | string | number | non | "20.00" | Facultatif. Les taxes déduites du revenu brut. Affiché seulement. |
ts | string | non | "2026-10-04T02:00:00Z" | Quand le chiffre a été déclaré. |
{
"status": "accepted",
"event_type": "ngr",
"event_id": "0199b2d1-5c0e-7b42-8a17-3e9d6f0c4b21",
"commission": {
"effect": "created",
"type": "revshare",
"amount_minor": 2960,
"status": "hold"
}
} Un click_id, un btag, un promo_code ou un player_id qui contient { ou } est refusé : cela signifie que votre plateforme a envoyé un placeholder sans le renseigner.
La réponse
Un événement qui a été enregistré, ou qui l'était déjà, reçoit un 200 et un objet JSON. Les champs qui ne s'appliquent pas sont omis.
| Champ | Type | Signification |
|---|---|---|
status | string | accepted, ou duplicate quand l'événement était déjà enregistré. |
event_type | string | Le type que vous avez envoyé. |
event_id | string | L'identifiant RevRake de l'événement enregistré, un UUID. Le même à chaque renvoi. |
attribution | object | Pour une inscription : la décision. |
attribution.attributed | boolean | Si le joueur appartient à un affilié. |
attribution.reason | string | Pourquoi. Voir le tableau ci-dessous. |
attribution.affiliate_number | integer | L'affilié. Seulement quand le joueur est attribué. |
attribution.link_number | integer | Le lien de l'affilié. Seulement quand le joueur est attribué. |
attribution.click_id | string | Le clic retenu, quand il y en a un. |
attribution.policy_version | integer | La version de la politique d'attribution de la marque qui a décidé. |
attribution.window_days | integer | La fenêtre d'attribution de cette version, en jours. |
attribution.model | string | last_click ou first_click : le modèle de cette version. |
commission | object | Pour un dépôt, un chargeback et ngr : ce que l'événement a fait au grand livre. |
commission.effect | string | created, cancelled (une commission en rétention a été rejetée), reversed (une ligne d'annulation a été ajoutée) ou none. |
commission.type | string | cpa, revshare, adjustment ou reversal. |
commission.amount_minor | integer | Le montant en unités mineures de la devise du deal (4000 vaut 40.00). Négatif pour une annulation et pour un ajustement à la baisse. |
commission.status | string | hold, approved ou rejected. |
commission.reason | string | Pourquoi rien n'a été créé, quand effect vaut none. Voir le tableau ci-dessous. |
waiting_for_player | boolean | true pour un dépôt dont le joueur n'est pas encore inscrit. Il est conservé et valorisé quand l'inscription arrive. |
duplicate_of | string | Pour une ancienne correspondance de premier dépôt entre événements en direct et anciens fichiers quotidiens : le event_id précédent. Les récapitulatifs SALES actuels utilisent une couverture quotidienne et conservent chaque identifiant de transaction réelle. |
detail | string | Avec duplicate_of : une phrase disant quel dépôt antérieur celui-ci répète. |
{
"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" }
} Une commission est créée avec le statut hold. Elle est approuvée automatiquement à la fin de la période de rétention du deal, sauf si quelque chose la retient encore : une alerte de fraude ouverte, un affilié qui n'est pas approuvé, ou un taux de change manquant.
Raisons d'attribution
Le click ID est essayé d'abord. S'il n'est pas l'un des vôtres, le btag est essayé. Quand la politique dit que le btag l'emporte et que le btag correspond à un lien, le btag est essayé d'abord. Un btag qui correspond à un lien attribue le joueur même quand aucun clic n'est trouvé. Un code promo est essayé en dernier, seulement si ni le click ID ni le btag n'ont attribué le joueur. La politique, sa fenêtre et lequel des deux l'emporte se règlent sur la page Intégration ; chaque changement est une nouvelle version. Quand la politique fait primer le code promo, un code qui correspond à un lien est essayé avant les deux, et un code qui ne correspond pas revient à eux. Un accord peut fixer sa propre fenêtre, qui remplace celle de la politique pour les clics sur les liens de ses affiliés.
reason | Signification | |
|---|---|---|
click | Attribué | Le click ID correspond à un clic dans la fenêtre. |
first_click | Attribué | La politique est au premier clic : le click ID correspond à un clic dans la fenêtre, et un clic compté plus ancien du même visiteur (même adresse et même appareil) dans la fenêtre a été crédité à sa place. |
btag_click | Attribué | Le btag correspond à un lien, et un clic sur ce lien a été trouvé dans la fenêtre. |
btag_only | Attribué | Le btag correspond à un lien ; aucun clic n'a été trouvé dans la fenêtre. |
promo_code | Attribué | Ni le click ID ni le btag n'ont attribué le joueur, et le code promo correspond au code d'un affilié approuvé. |
no_tag | Non attribué | L'inscription ne portait ni click ID ni btag. |
unknown_click | Non attribué | Le click ID n'est pas l'un des vôtres, et aucun btag n'a été envoyé. |
unknown_btag | Non attribué | Le btag est mal formé ou ne correspond à aucun lien. |
outside_window | Non attribué | Le clic est plus ancien que la fenêtre d'attribution, ou postérieur à l'inscription. |
affiliate_inactive | Non attribué | L'affilié n'est pas approuvé, ou ne l'était pas au moment du clic. |
unknown_promo_code | Non attribué | Seul un code promo a été envoyé, et il ne correspond à aucun de vos codes. |
promo_code_retired | Non attribué | Seul un code promo a été envoyé, et il a été retiré. |
Pourquoi aucune commission n'a été créée
commission.reason | Signification |
|---|---|
unattributed | Le joueur n'appartient à aucun affilié. |
not_first | Ce n'est pas le premier dépôt du joueur. |
already_earned | Le CPA du joueur a déjà été gagné. Un second « premier » dépôt ne paie rien et déclenche une alerte. |
no_deal_version | L'affilié n'a pas de deal, ou le deal n'avait pas de version au moment de l'événement. |
country_blocked | Le joueur vient d'un pays pour lequel le deal ne paie pas. Il reste enregistré et attribué. |
no_cpa_in_deal | Le deal ne paie pas de CPA. |
below_threshold | Le premier dépôt ou les dépôts cumulés nets restent sous le minimum du deal, selon sa base CPA. |
no_commission | Pour un chargeback : le dépôt n'avait rien rapporté. |
no_revshare_in_deal | Pour ngr : le deal ne paie pas de RevShare. |
fx_rate_missing | Pour ngr : il n'y a pas encore de taux de change pour la période. La déclaration est enregistrée et valorisée quand un taux existe. |
unchanged | Pour ngr : un chiffre corrigé qui ne change rien à la commission. |
Lots
Le corps peut être un tableau JSON de 1 à 1 000 événements, envoyé au même endpoint avec les mêmes en-têtes. La signature porte sur le tableau entier. Les événements sont traités dans l'ordre, chacun séparément, de sorte qu'un événement refusé n'arrête jamais les autres.
Un lot qui a pu être lu reçoit un 200, même quand tous ses événements ont été refusés. Regardez les compteurs.
[
{"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
} | Champ | Type | Signification |
|---|---|---|
results | array | Une entrée par événement, dans l'ordre d'envoi. |
results[].index | integer | La position de l'événement dans le tableau, à partir de 0. |
results[].status | string | accepted, duplicate ou rejected. |
results[].event_type | string | Comme dans une réponse simple. Absent pour un événement refusé. |
results[].event_id | string | Comme dans une réponse simple. Absent pour un événement refusé. |
results[].attribution | object | Comme dans une réponse simple. |
results[].commission | object | Comme dans une réponse simple. |
results[].waiting_for_player | boolean | Comme dans une réponse simple. |
results[].field | string | Pour un événement refusé : le champ à corriger. |
results[].message | string | Pour un événement refusé : ce qu'il faut corriger. |
accepted | integer | Combien d'événements ont été enregistrés. |
duplicate | integer | Combien étaient déjà enregistrés. |
rejected | integer | Combien ont été refusés. |
POST /v1/files
Envoie un fichier CSV quotidien, au lieu de l'importer sur la page Intégration ou de laisser RevRake le récupérer à une adresse où votre plateforme le publie. Le corps est le fichier lui-même ; les en-têtes et la signature sont ceux d'un événement, et la signature porte sur le timestamp et le fichier. Le nom du fichier va dans le paramètre de query filename ; il est affiché dans le portail et ne sert à rien d'autre.
POST https://app.revrake.com/v1/files?filename=sales-2026-10-03.csv La ligne d'en-tête détermine de quel fichier il s'agit : un fichier avec une colonne registration_date est un fichier REG, un fichier avec une colonne activitydate est un fichier SALES. Les noms de colonnes sont comparés sans tenir compte de la casse. Les colonnes qui ne sont pas listées ci-dessous peuvent rester dans le fichier ; elles sont ignorées.
Formats acceptés : YYYY-MM-DD, YYYY-MM-DD HH:MM:SS, YYYY-MM-DDTHH:MM:SS, RFC 3339 ou YYYY/MM/DD. Sans décalage UTC, le fuseau des fichiers défini dans les Paramètres s’applique (UTC par défaut). Un horodatage avec décalage désigne un instant précis ; pour SALES, son jour civil dans le fuseau des fichiers est retenu. Le jour et le mois ne sont jamais devinés : 30/09/2026 est refusé.
Fichier REG : une ligne par joueur inscrit
| Colonne | Obligatoire | Signification |
|---|---|---|
registration_date | oui | Quand le joueur s'est inscrit. Devient ts. |
player_id | oui | Votre identifiant du joueur. |
btag | oui | Le btag stocké sur le joueur. Peut être vide : le joueur n'est alors pas attribué, sauf si un code promo l'attribue. |
promo_code | non | Facultatif. Le code promo que le joueur a saisi à l'inscription, utilisé comme promo_code d'une inscription. |
player_country | non | Facultatif. Le code pays du joueur sur deux lettres (ISO 3166-1 alpha-2), utilisé comme country d'une inscription. Vide : le pays du clic. |
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 Fichier SALES : une ligne par joueur et par jour
| Colonne | Obligatoire | Signification |
|---|---|---|
activitydate | oui | Le jour d’activité, déterminé dans le fuseau des fichiers de l’espace de travail. |
player_id | oui | Votre identifiant du joueur. |
currency | oui | La devise des montants de la ligne. Vide : la devise de reporting de l'espace de travail. |
deposits | oui | Total brut des dépôts du jour, y compris le premier dépôt effectué ce jour-là. Ce n’est pas un cumul historique ; ne déduisez pas les chargebacks. |
first_deposit_amount | oui | Montant du premier dépôt, uniquement le jour où il a eu lieu ; zéro les autres jours. Déjà compris dans deposits, jamais ajouté une seconde fois. Il ne peut dépasser le total brut des dépôts du jour. |
chargeback | oui | Total des chargebacks de ce jour d’activité, séparé des dépôts bruts. Ce n’est pas un cumul historique. Il réduit les dépôts cumulés pour le CPA, sans identifier une transaction précise. |
*_net_revenue | non | Toute colonne nommée net_revenue ou dont le nom se termine par _net_revenue. Les cellules renseignées sont additionnées dans le revenu net du joueur pour ce jour, déclaré comme ngr. Une ligne où aucune n'est renseignée ne déclare aucun revenu. |
*_gross_revenue | non | Facultatif. Les colonnes nommées gross_revenue ou dont le nom se termine par _gross_revenue, additionnées dans le ggr du ngr du jour. Montré à l'affilié seulement. |
*_bonus | non | Facultatif. Les colonnes nommées bonus ou dont le nom se termine par _bonus, additionnées dans bonuses. Affiché seulement. |
*_fees | non | Facultatif. Les colonnes nommées fees ou dont le nom se termine par _fees, additionnées dans fees. Affiché seulement. |
*_taxes | non | Facultatif. Les colonnes nommées taxes ou dont le nom se termine par _taxes, additionnées dans taxes. Affiché seulement. |
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, - Chaque ligne SALES enregistre un récapitulatif monétaire quotidien et, si des cellules de revenu sont remplies, un événement NGR distinct. Ils sont traités indépendamment : refuser le récapitulatif monétaire n’annule pas le revenu accepté, ni l’inverse. Vérifiez tous les problèmes dans la réponse.
- Un récapitulatif par marque, joueur et jour d’activité ; la première devise acceptée est définitive. Des montants identiques sont des replays, même après renommage ou réordonnancement du fichier. Modifier les montants, la devise ou les limites horaires d’un jour accepté crée un conflit, y compris pour des zéros. Les montants déjà enregistrés restent inchangés.
deposits,first_deposit_amountetchargebacksont obligatoires. Une cellule vide vaut zéro. Les montants doivent être des décimaux non négatifs respectant la précision de la devise de la ligne. Confirmez ces définitions avec votre plateforme avant de connecter son export.- Envoyez REG avant SALES. Les récapitulatifs monétaires reçus avant sont conservés et calculés à l’arrivée de l’inscription. Le NGR d’un joueur inconnu est refusé : après REG, renvoyez SALES ou NGR. Le récapitulatif monétaire conservé sera un replay.
- Le récapitulatif couvre les postbacks individuels de son jour d’activité et de sa devise dans le fuseau des fichiers, sans additionner les montants deux fois. Les identifiants de transaction restent utilisables comme références. Des dépôts ou chargebacks connus dépassant le récapitulatif, ou des preuves contradictoires du premier dépôt, créent un conflit.
- Pour le CPA cumulé, les dépôts moins les chargebacks doivent atteindre le minimum du deal. Chaque flux quotidien utilise le taux de change de sa date d’activité ; chaque postback utilise son propre jour UTC. Sans taux, le règlement reste en rétention sous
fx_rate_missing. Un taux de chargeback manquant bloque le paiement souschargeback_fx_missingjusqu’au rapprochement, même pour les commissions déjà incluses dans un paiement. - Pour le CPA sur premier dépôt, un chargeback agrégé peut ne pas identifier le dépôt annulé. Un récapitulatif monétaire ambigu d’un joueur déjà inscrit est refusé. S’il est arrivé avant REG, il est conservé et l’inscription réussit, mais le CPA créé reste en rétention sous
chargeback_reference_missing. Pour vérifier la référence de transaction, envoyez un chargeback dontref_txn_idcontient l’identifiant de transaction du dépôt initial. - Le revenu est distinct des totaux monétaires immuables : modifier le NGR quotidien constitue une rectification, et la différence de commission devient un ajustement.
La réponse
Un fichier lisible renvoie 200. Les compteurs portent sur les événements, pas seulement les lignes : une ligne SALES peut enregistrer séparément un récapitulatif monétaire et du NGR, avec un succès partiel. Vérifiez toujours rejected et 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."]
} | Champ | Type | Signification |
|---|---|---|
id | string | L'identifiant RevRake de cet import. |
filename | string | Le nom que vous avez donné, ou reg.csv / sales.csv. |
kind | string | reg ou sales. |
uploaded_at | string | Quand il a été reçu. |
rows_total | integer | Lignes de données dans le fichier. |
accepted | integer | Événements enregistrés. |
duplicates | integer | Événements déjà enregistrés. |
rejected | integer | Lignes ou événements refusés. Chacun figure dans le journal des entrées, avec la ligne elle-même. |
skipped | integer | Lignes sans rien à enregistrer. |
problems | array of string | Les 20 premières lignes refusées, sous la forme line N: reason. Omis quand il n'y en a pas. |
GET /v1/reports
Renvoie le rapport de la page Rapports : clics, clics signalés, inscriptions, premiers dépôts et gains, groupés d'une seule façon, pour les jours jusqu'à aujourd'hui dans le fuseau horaire de l'espace de travail. Les chiffres du jour sont actualisés quand un rapport est demandé, au plus toutes les 30 secondes sur un programme chargé.
GET https://app.revrake.com/v1/reports?by=link&days=7 | Paramètre | Type | Exemple | Signification |
|---|---|---|---|
by | string | link | Comment les lignes sont groupées : day, link, sub1, country ou affiliate. Par défaut day. Quand affiliate est renseigné, by=affiliate est traité comme day. |
days | integer | 7 | Combien de jours, aujourd'hui compris : de 1 à 365. Par défaut 30. |
from | string | 2026-09-01 | Le premier jour d'une période quelconque, YYYY-MM-DD dans le fuseau horaire de l'espace de travail. Avec from ou to, days est ignoré. 366 jours au plus. |
to | string | 2026-09-30 | Le dernier jour de la période, inclus. Par défaut aujourd'hui. |
affiliate | integer | 1001 | Un numéro d'affilié. Restreint le rapport à cet affilié. Clé opérateur uniquement ; ignoré avec une clé affilié, qui lit toujours son propre affilié. |
tag | string | Influencers | Le nom d'un groupe, comme sur la page Groupes (répétez-le pour plusieurs : l'un d'eux). Clé de l'opérateur uniquement ; ignoré avec affiliate ou une clé d'affilié. Un nom inconnu donne 422 unknown_tag. |
format | string | csv | csv renvoie un fichier CSV au lieu de 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
}
} | Champ | Type | Signification |
|---|---|---|
by | string | Le groupement qui a été utilisé. |
from | string | Le premier jour du rapport, YYYY-MM-DD. |
to | string | Le dernier jour : aujourd'hui dans le fuseau horaire de l'espace de travail, ou le to que vous avez donné. |
currency | string | La devise de reporting de l'espace de travail. Les gains sont dans cette devise. |
rows | array | Une entrée par groupe. |
rows[].key | string | Ce qui identifie le groupe : le jour, l'identifiant RevRake du lien ou de l'affilié, la valeur de sub1, ou le pays en deux lettres. |
rows[].label | string | Le texte que le portail affiche pour le groupe : le jour, le libellé de campagne du lien, la valeur de sub1, le pays, ou le nom et le numéro de l'affilié. |
rows[].clicks | integer | Clics propres. |
rows[].flagged_clicks | integer | Clics signalés comme bots, répétitions, rafales, ou d'un affilié qui n'est pas approuvé. Non comptés dans clicks. |
rows[].registrations | integer | Joueurs attribués. |
rows[].ftds | integer | Premiers dépôts. |
rows[].earnings_minor | integer | Commissions gagnées, en unités mineures de la devise de reporting, au taux du jour où chacune a été gagnée. |
total | object | La somme des lignes, sous la forme d'une ligne. |
En CSV
Avec format=csv, la réponse est un fichier. Sa première colonne porte le nom du groupement et contient le libellé ; viennent ensuite clicks, flagged_clicks, registrations, first_deposits et earnings_<currency> en décimal. La dernière ligne est le total.
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
Renvoie une page du grand livre des commissions, les plus récentes d'abord sauf si vous triez autrement. Le montant d'une ligne n'est jamais modifié et une ligne n'est jamais supprimée, mais son status change après son écriture : hold, puis approved, puis paid, ou rejected. Une synchronisation doit relire une période et mettre à jour les lignes d'après leur id, pas seulement récupérer les nouvelles lignes.
GET https://app.revrake.com/v1/commissions?from=2026-09-01&to=2026-10-01&per_page=500 | Paramètre | Type | Exemple | Signification |
|---|---|---|---|
status | string | approved | hold, approved, paid ou rejected. Par défaut : tous. |
from | string | 2026-09-01 | Seulement les lignes survenues à cet instant ou après : RFC 3339, ou un jour YYYY-MM-DD en UTC. |
to | string | 2026-10-01 | Seulement les lignes survenues avant cet instant. Mêmes formats. |
affiliate | integer | 1001 | Un numéro d'affilié. Restreint les lignes, totals et owed à cet affilié. Clé opérateur uniquement ; ignoré avec une clé affilié. |
tag | string | Influencers | Le nom d'un groupe, comme sur la page Groupes (répétez-le pour plusieurs : l'un d'eux). Clé de l'opérateur uniquement ; ignoré avec affiliate ou une clé d'affilié. Un nom inconnu donne 422 unknown_tag. |
q | string | PLR-1001 | Les lignes dont l'identifiant du joueur ou le nom de l'affilié contient ce texte. Jusqu'à 100 caractères. |
sort | string | when | when, affiliate, player, status, deposit ou commission. Par défaut when. |
dir | string | asc | asc ou desc. Par défaut desc. |
page | integer | 2 | La page, à partir de 1. Par défaut 1. |
per_page | integer | 500 | 10, 25, 50, 100, 500 ou 1000. Par défaut 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
} | Champ | Type | Signification |
|---|---|---|
currency | string | La devise de reporting de l'espace de travail. |
totals | object | La somme par statut, en unités mineures de la devise de reporting : sur tout le grand livre, ou sur la période quand from ou to est donné. Non restreinte par les autres filtres, sauf affiliate. Les lignes qui attendent encore un taux de change n'y figurent pas. |
owed | object | La somme par devise et par statut, dans la devise propre à chaque commission : ce qui est dû. Sur les mêmes lignes que totals. |
period | boolean | true quand from ou to a été donné : totals et owed ne couvrent alors que cette période. |
commissions | array | Les lignes de cette page. |
total | integer | Combien de lignes correspondent aux filtres. |
page | integer | La page qui a été renvoyée. |
per_page | integer | Le nombre de lignes par page qui a été utilisé. |
Une ligne de commission
| Champ | Type | Signification |
|---|---|---|
id | string | L'identifiant RevRake de la ligne, un UUID. Il ne change jamais : mettez à jour d'après lui. |
occurred_at | string | Quand la commission a été gagnée : l'heure du dépôt, la fin de la période de revenu, ou l'heure du chargeback. |
type | string | cpa, revshare, adjustment, reversal ou tier. |
amount_minor | integer | La commission, en unités mineures de currency. Négative pour une annulation et pour un ajustement à la baisse. |
currency | string | La devise de la commission : celle du deal. |
reporting_minor | integer | null | La commission dans la devise de reporting de l'espace de travail, au taux du jour où elle a été gagnée. null tant que ce taux manque. |
gross_minor | integer | Le dépôt ou le revenu net à l'origine de la commission, en unités mineures de gross_currency. |
gross_currency | string | La devise du dépôt ou du revenu. |
rate_snapshot | integer | Les conditions qui ont été appliquées : le montant du CPA en unités mineures, ou le RevShare en centièmes de pour cent (2500 vaut 25 %). |
status | string | hold, approved, paid ou rejected. Voir les statuts d'une commission. |
status_reason | string | Pourquoi une ligne est encore en rétention ou a été rejetée. Vide sinon. Toutes les valeurs figurent dans le tableau des raisons. |
status_note | string | La note de l'opérateur sur une commission retirée, telle que l'affilié la lit. Vide sinon. |
hold_until | string | null | Quand la période de rétention se termine. null pour une annulation. |
affiliate_number | integer | Le numéro de l'affilié. |
affiliate_name | string | Le nom de l'affilié. |
player_ref | string | Votre identifiant du joueur. |
deal_name | string | Le deal. |
deal_version | integer | La version du deal qui a valorisé la ligne. |
Listes du programme : affiliés, liens, accords
Votre backend peut lister le programme tel que le portail le montre, signé comme les autres lectures et compté dans la même limite. GET /v1/affiliates et GET /v1/deals demandent la clé de l'opérateur ; avec une clé d'affilié ils répondent 403 operator_key_required. GET /v1/links répond les liens de la marque, ou ceux d'un affilié avec affiliate=<numéro> ; avec une clé d'affilié, les siens.
Les listes sont paginées avec page (à partir de 1) et per_page (de 1 à 500, 100 par défaut) et portent total. GET /v1/affiliates accepte aussi status : pending, approved, rejected ou suspended. Créer des affiliés ou des liens par l'API n'est pas encore proposé : dites-nous à quoi cela vous servirait.
GET https://app.revrake.com/v1/links?affiliate=1001&per_page=100 Chaque affilié
| Champ | Type | Signification |
|---|---|---|
number | integer | Le numéro d'affilié, la première partie du btag ; dans un lien, le numéro de lien, sa seconde partie. |
name | string | Le nom de l'affilié. |
email | string | L'adresse e-mail de l'affilié. |
status | string | pending, approved, rejected ou suspended. |
deal | string | Le nom de l'accord de l'affilié ; vide avant l'approbation. |
created_at | string | Date de création, RFC 3339. |
decided_at | string | null | Quand la candidature a été approuvée ou refusée, ou le compte suspendu ; null avant. |
Chaque lien
| Champ | Type | Signification |
|---|---|---|
affiliate_number | integer | Le numéro de l'affilié auquel appartient le lien. |
number | integer | Le numéro d'affilié, la première partie du btag ; dans un lien, le numéro de lien, sa seconde partie. |
code | string | Le code dans l'adresse du lien. |
url | string | Le lien de suivi, sur le domaine de suivi vérifié de la marque ou le domaine partagé. |
btag | string | <affiliate_number>_<number>. |
campaign | string | Le libellé de campagne du lien. |
landing_path | string | null | La page de votre site où mène le lien ; null pour celle de la marque par défaut. |
subs | string[5] | sub1 à sub5 fixés sur le lien ; chaînes vides s'ils ne le sont pas. |
promo_code | string | null | Le code promo, sur un lien créé pour un code ; sinon null. |
vanity_url | string | null | L'adresse courte /go/<nom>, si l'affilié en a choisi une ; sinon null. |
created_at | string | Date de création, RFC 3339. |
Chaque accord
| Champ | Type | Signification |
|---|---|---|
name | string | Le nom de l'affilié. |
currency | string | La devise dans laquelle l'accord rémunère et paie. |
listed | boolean | Si la page publique d'inscription montre l'accord. |
default | boolean | Si les nouveaux affiliés reçoivent cet accord. |
version | integer | La version de l'accord en vigueur. |
effective_at | string | Quand cette version est entrée en vigueur, RFC 3339. |
terms | object | Les conditions de cette version : montants en unités mineures, parts en points de base (2500 = 25 %), jours de retenue, règle des mois négatifs, fenêtre d'attribution propre à l'accord, paliers. |
Export vers l’entrepôt de données
Réglé sur la page Intégration : chaque nuit, RevRake écrit la veille de chaque marque dans votre propre bucket, sur tout service compatible S3, à <dossier>/<marque>/<AAAA-MM-JJ>/, le jour étant compté dans le fuseau horaire de l’espace de travail. Quatre fichiers CSV compressés en gzip (UTF-8, une ligne d’en-tête, guillemets selon la RFC 4180), puis manifest.json. Le manifeste est écrit en dernier : chargez un jour une fois qu’il existe, et vérifiez rows, bytes et sha256 de chaque fichier.
Une ligne appartient au jour où elle est arrivée (un clic : quand il a eu lieu) : un fichier quotidien en retard est dans le jour où il est arrivé, jamais perdu. Les heures sont en RFC 3339, UTC avec millisecondes ; les montants sont des décimaux dans leur devise. Les statuts sont ceux du moment de l’export : celui d’une commission change ensuite, relisez donc GET /v1/commissions pour le statut actuel. Un jour en échec est réessayé toutes les heures et rattrapé jusqu’à sept jours en arrière ; réexporter un jour écrase ses fichiers. De nouvelles colonnes peuvent être ajoutées en fin de fichier ; schema_version du manifeste change quand un chargeur doit changer.
manifest.json : schema_version, workspace, brand, day, timezone, from et to (les bornes du jour en UTC), generated_at et files : pour chacun, name, rows, bytes, sha256 (du fichier compressé).
clicks.csv.gz : tous les clics sur les liens de la marque ce jour-là, signalés compris.
| Champ | Type | Signification |
|---|---|---|
click_id | string | L’identifiant de clic, tel que passé à votre page d’arrivée et dans les postbacks. |
clicked_at | string | Quand le clic a eu lieu. |
affiliate_number | integer | Le numéro d’affilié. |
link_number | integer | Le numéro de lien. |
btag | string | <affiliate_number>_<link_number>. |
country | string | Code pays à deux lettres ; vide s’il est inconnu. |
device | string | desktop, mobile, tablet ou bot, d’après le navigateur. |
os | string | Le système d’exploitation, d’après le navigateur. |
browser | string | Le navigateur. |
sub1 … sub5 | string | sub1 à sub5 : les sous-identifiants du clic. |
utm_source … utm_content | string | utm_source à utm_content : les balises UTM du clic. |
gclid, fbclid, ttclid, msclkid, wbraid | string | gclid, fbclid, ttclid, msclkid, wbraid : identifiants de clic des régies publicitaires dans l’URL d’arrivée. |
referer | string | La page d’où venait le visiteur. |
flags | string | Pourquoi le clic n’est pas compté, séparé par ; : bot, duplicate, burst, inactive. Vide pour un clic propre. |
players.csv.gz : les joueurs dont l’inscription est arrivée ce jour-là.
| Champ | Type | Signification |
|---|---|---|
player_id | string | Votre identifiant de joueur. |
registered_at | string | L’heure d’inscription que vous avez envoyée. |
arrived_at | string | Quand RevRake l’a enregistrée. |
country | string | Code pays à deux lettres ; vide s’il est inconnu. |
attributed | boolean | true quand un affilié est crédité. |
attribution_reason | string | Pourquoi, comme dans la réponse du postback : click, btag_only, promo_code, no_tag… |
affiliate_number | integer | Le numéro d’affilié. |
link_number | integer | Le numéro de lien. |
btag | string | <affiliate_number>_<link_number>. |
click_id | string | Le clic qui a crédité le joueur ; vide s’il n’y en a pas. |
policy_version | integer | La version de la politique d’attribution qui a décidé. |
events.csv.gz : tous les événements acceptés de la marque arrivés ce jour-là, y compris les récapitulatifs quotidiens SALES, avec leur contenu.
| Champ | Type | Signification |
|---|---|---|
event_id | string | L’identifiant de l’événement dans RevRake. |
type | string | registration, deposit, chargeback, daily_sales ou ngr ; pour une commission, cpa, revshare, tier, adjustment ou reversal. |
external_id | string | La clé de l’événement : l’identifiant du joueur, de la transaction, ou joueur et période. |
player_id | string | Votre identifiant de joueur. |
occurred_at | string | Quand c’est arrivé, selon votre envoi ; pour une commission, quand elle a été gagnée. |
received_at | string | Quand RevRake a accepté l’événement. |
source | string | s2s (l’API) ou file (un fichier quotidien). |
payload | JSON | L’événement tel que RevRake l’a lu, en JSON. |
result | JSON | Ce que RevRake a répondu, en JSON. |
commissions.csv.gz : les lignes de commission écrites ce jour-là.
| Champ | Type | Signification |
|---|---|---|
commission_id | string | L’identifiant de la ligne, l’id de GET /v1/commissions. |
created_at | string | Quand la ligne a été écrite. |
occurred_at | string | Quand c’est arrivé, selon votre envoi ; pour une commission, quand elle a été gagnée. |
type | string | registration, deposit, chargeback, daily_sales ou ngr ; pour une commission, cpa, revshare, tier, adjustment ou reversal. |
status | string | hold, approved, paid ou rejected, au moment de l’export. |
status_reason | string | Pourquoi elle est retenue ou refusée ; vide sinon. |
affiliate_number | integer | Le numéro d’affilié. |
player_id | string | Votre identifiant de joueur. |
deal | string | Le nom de l’accord. |
deal_version | integer | La version de l’accord qui l’a valorisée. |
gross | decimal | Le dépôt ou le revenu net derrière elle. |
gross_currency | string | Sa devise. |
amount | decimal | La commission. |
currency | string | La devise de l’accord. |
reporting_amount | decimal | La commission dans la devise de reporting ; vide tant que le taux de change manque. |
reporting_currency | string | La devise de reporting de l’espace de travail. |
reverses_id | string | Pour une annulation, la ligne annulée. |
payout_item_id | string | La ligne de paiement qui l’a reprise, une fois le mois clôturé. |
Idempotence
Chaque événement possède une clé naturelle. Un nouvel envoi identique renvoie la réponse conservée avec "status":"duplicate". La réponse d’un dépôt en attente d’inscription est mise à jour à son arrivée. Des données monétaires modifiées peuvent créer un conflit ; les rectifications NGR utilisent des révisions. Après un délai dépassé, réessayez avec un nouvel horodatage de signature.
| Événement | Clé | La même clé à nouveau |
|---|---|---|
registration | player_id | La première réponse. L'attribution n'est pas décidée à nouveau, même si les tags diffèrent. |
deposit | txn_id | La réponse conservée, mise à jour à l’arrivée de l’inscription attendue. Modifier le joueur, le montant ou la devise crée un conflit. Un récapitulatif SALES couvrant la transaction ne supprime pas son identifiant. |
chargeback | txn_id | La première réponse. Un second chargeback du même dépôt sous un nouveau txn_id est refusé. |
ngr | player_id et period | Même montant et même devise : la première réponse. Un montant différent : une correction, enregistrée comme une nouvelle révision, avec la différence en adjustment. |
| CSV | Ligne REG : player_id | Comme une registration. |
| CSV | Récapitulatif monétaire SALES : marque, joueur et jour d’activité | Des totaux identiques sont des replays. Modifier les dépôts, le premier dépôt, les chargebacks, la devise ou les limites du jour crée un conflit, même pour un récapitulatif initialement nul. |
| CSV | Ligne SALES, revenu : le joueur et le jour | Comme ngr : un chiffre modifié dans un réexport est une correction. |
Statuts et erreurs
Toutes les réponses que l'API peut donner et tous les statuts qu'un enregistrement peut avoir, au même endroit. Une erreur reçoit un objet JSON : error (le code), message (une phrase en anglais) et, pour invalid, field.
{"error":"invalid","field":"amount","message":"amount must be a positive decimal in KES, for example 25.00."} Statuts HTTP et codes d'erreur
| Statut | error | Endpoint | Quand | Que faire |
|---|---|---|---|---|
| 200 | – | /v1/* | La requête a été traitée. Pour un événement : enregistré, ou déjà enregistré. Pour un lot ou un fichier : lu ; regardez les compteurs, certains éléments ont pu être refusés. | |
| 400 | bad_request | POST /v1/postback | Le corps commence comme un tableau mais n'est pas un tableau JSON d'événements. | Corrigez la requête. La même requête renvoyée reçoit la même réponse. |
| 401 | unknown_key | /v1/* | La clé dans X-RevRake-Key est inconnue ou révoquée, ou c'est une clé affilié sur un endpoint d'écriture. | Utilisez la clé actuelle. La renvoyer ne sert à rien. |
| 401 | bad_timestamp | /v1/* | X-RevRake-Timestamp est absent, n'est pas un nombre entier de secondes, ou est décalé de plus de cinq minutes. | Vérifiez l'horloge et le code de signature, puis renvoyez-la avec un timestamp frais. |
| 401 | bad_signature | /v1/* | La signature ne correspond pas au timestamp et au corps (pour une lecture : au chemin et à la query). | Vérifiez l'horloge et le code de signature, puis renvoyez-la avec un timestamp frais. |
| 403 | affiliate_inactive | GET /v1/* | Une lecture avec une clé affilié dont l'affilié n'est pas approuvé dans le programme : en attente, rejeté ou suspendu. | Rien à corriger dans la requête : le compte doit être approuvé par l'opérateur. |
| 404 | unknown_affiliate | GET /v1/* | Une lecture avec une clé opérateur : aucun affilié ne porte le numéro donné dans affiliate. | Corrigez la requête. La même requête renvoyée reçoit la même réponse. |
| 405 | – | /v1/* | L'endpoint n'accepte pas cette méthode. Pas de corps JSON. | Corrigez la requête. La même requête renvoyée reçoit la même réponse. |
| 413 | too_large | POST /v1/* | Le corps dépasse la limite de l'endpoint. | Corrigez la requête. La même requête renvoyée reçoit la même réponse. |
| 422 | invalid | POST /v1/*, GET /v1/reports | L'événement ou le fichier ne peut pas être utilisé tel quel. | Corrigez la requête. La même requête renvoyée reçoit la même réponse. |
| 429 | rate_limited | GET /v1/* | Plus de lectures que le quota de la clé. La réponse porte Retry-After. | Attendez le nombre de secondes indiqué dans Retry-After, puis renvoyez-la. |
| 500 | internal | /v1/* | Quelque chose s'est mal passé de notre côté. | Renvoyez-la. |
- Un lot sans événement ou de plus de 1 000 événements est refusé avec un
422invalid, sansfield. - Un
401pour un timestamp ou une signature incorrects avec une clé opérateur figure dans le journal des entrées commebad_signature. Une requête avec une clé inconnue, ou avec une clé affilié, n'est pas journalisée. - Une lecture ne répond
422que pour une période de rapport inutilisable (frometto). Tout autre paramètre dont la valeur n'est pas autorisée est ignoré et sa valeur par défaut est utilisée. Vérifiezby,pageetper_pagedans la réponse. - Réessayez sur un délai dépassé, sur un
429et sur un500. Ne renvoyez aucun autre4xxinchangé.
Ce que field désigne dans un 422
field | Quand |
|---|---|
body | Le corps n'est pas du JSON valide, ou porte un champ inconnu ou mal formé (par exemple un ts qui n'est pas au format RFC 3339). |
type | type est absent ou n'est pas l'un des quatre. |
player_id | Absent ou de plus de 100 caractères ; un placeholder qui n'a pas été renseigné ; pour ngr, un joueur qui n'est pas inscrit. |
click_id | Un placeholder qui n'a pas été renseigné. Le message commence par misconfigured_macro. |
btag | Un placeholder qui n'a pas été renseigné. Le message commence par misconfigured_macro. |
promo_code | Un placeholder qui n'a pas été renseigné. Le message commence par misconfigured_macro. |
txn_id | Absent ou de plus de 200 caractères. |
ref_txn_id | Absent ; aucun dépôt avec ce txn_id n'est connu ; ou le dépôt a déjà fait l'objet d'un chargeback. |
amount | Pas un décimal que la devise autorise ; pour un dépôt, pas supérieur à zéro. |
currency | Pas un code à trois lettres. |
ggr | Pour ngr : pas un montant décimal dans la devise. |
bonuses | Pour ngr : pas un montant décimal dans la devise. |
fees | Pour ngr : pas un montant décimal dans la devise. |
taxes | Pour ngr : pas un montant décimal dans la devise. |
ts | À plus d'un jour dans le futur. |
period | Ni un jour ni un mois, ou dans le futur. |
from | Pour GET /v1/reports : from ou to n'est pas au format YYYY-MM-DD, from est après to, ou ils sont distants de plus de 366 jours. |
file | Pour /v1/files : le fichier est vide, n'est pas du CSV, n'est ni un fichier REG ni un fichier SALES, n'a pas une colonne obligatoire, ou compte plus de 200 000 lignes. |
chargeback | Dans un fichier SALES : la cellule chargeback ne peut pas être appliquée. Le message dit pourquoi. |
Le statut d'un événement
Dans la réponse à un événement, et par événement dans les results d'un lot.
status | Signification |
|---|---|
accepted | Enregistré maintenant. La réponse dit ce qu'il a produit. |
duplicate | Déjà conservé sous la même clé ; un replay identique ne change rien. Une ancienne correspondance de premier dépôt entre canaux peut aussi renvoyer duplicate_of. Les récapitulatifs SALES actuels conservent les transactions réelles des postbacks et ne comptent les montants quotidiens couverts qu’une fois. |
rejected | Seulement dans un lot : l'événement a été refusé, avec field et message. Un événement seul qui est refusé reçoit un 422. |
L'effet d'un événement sur le grand livre
commission.effect | Signification |
|---|---|
created | Une ligne de commission a été créée : un CPA, un RevShare, ou un ajustement pour un chiffre corrigé. |
cancelled | Un chargeback a rejeté une commission encore en rétention. |
reversed | Un chargeback a ajouté une ligne d'annulation en regard d'une commission déjà approuvée ou payée. |
none | Aucune ligne n'a été créée. reason dit pourquoi. |
Types de commission
type | Signification |
|---|---|
cpa | Une par joueur lorsque le minimum du deal est atteint par le premier dépôt ou les dépôts cumulés nets de chargebacks, selon sa base CPA. |
revshare | Une part du revenu net de jeu (NGR) d'un joueur pour une période. Négative pour une période où le joueur a gagné. |
adjustment | La différence que produit un chiffre de revenu corrigé. |
reversal | L'opposé d'une commission reprise après son approbation ou son paiement : par un chargeback, ou par l'opérateur avec un motif. Elle est approuvée tout de suite et se déduit du paiement suivant. |
tier | Un complément issu d'un palier de volume du deal : dès qu'un affilié amène assez de nouveaux joueurs déposants dans un mois civil, la différence entre le taux du palier et le taux de base est ajoutée à côté de chaque commission de ce mois. Il attend dans la même rétention que sa commission, ou est approuvé tout de suite si elle l'est déjà. Négatif quand il reprend un complément antérieur, après le rejet ou l'annulation de sa commission. |
Statuts d'une commission
Une ligne est écrite une fois et ses montants ne changent jamais. Son statut, lui, change :
status | Signification |
|---|---|
hold | En attente : de la fin de la période de rétention du deal, ou de ce que status_reason désigne. |
approved | La période de rétention est terminée et rien ne retient la ligne. Elle entre dans le prochain lot de paiement mensuel. Les annulations et certains ajustements sont approuvés dès le départ. |
paid | L'élément de paiement qui contient la ligne a été marqué comme payé. |
rejected | Elle ne sera pas payée. status_reason dit pourquoi, et status_note porte la note de l'opérateur quand il y en a une. |
Valeurs de status_reason
Vide si la ligne attend seulement sa période de rétention, et normalement pour les commissions approuvées ou payées. Un taux de chargeback manquant peut aussi bloquer une ligne approuvée. Les rétentions pour fraude attendent l’opérateur ou l’expiration configurée du signalement.
status_reason | Avec le statut | Signification |
|---|---|---|
fx_rate_missing | hold | Un taux de change nécessaire manque. Le règlement attend ce taux ; les flux quotidiens SALES utilisent leur date d’activité, les postbacks individuels leur jour UTC. |
chargeback_fx_missing | hold, approved, paid | Un chargeback ne peut pas encore être évalué. Le CPA et ses compléments de palier ne peuvent intégrer un nouveau paiement ni être marqués payés dans un paiement existant avant l’arrivée du taux et la fin du rapprochement. |
chargeback_reference_missing | hold | Un récapitulatif reçu avant l’inscription contient un chargeback agrégé qui n’identifie pas le dépôt annulé pour le CPA sur premier dépôt. L’inscription et le récapitulatif sont conservés ; le CPA créé attend en rétention la vérification de la référence de transaction. |
self_referral | hold | Une alerte de fraude ouverte : le joueur semble être l'affilié lui-même. Attend que l'opérateur lève ou confirme l'alerte. |
click_velocity | hold | Une alerte de fraude ouverte, ou un clic qui faisait partie d'une rafale : plus de clics sur un lien depuis une même adresse en une minute que la marque n'en autorise. Attend l'opérateur. |
duplicate_conversion | hold | Une alerte de fraude ouverte : un second « premier » dépôt a été déclaré pour le joueur. Attend l'opérateur. |
paid_traffic | hold | Une alerte de fraude ouverte : le clic qui a amené le joueur portait le click ID d'un réseau publicitaire. Attend l'opérateur. |
disposable_email | hold | Une alerte de fraude ouverte : le joueur s'est inscrit avec un domaine d'e-mail jetable. Attend l'opérateur. |
geo_mismatch | hold | Une alerte de fraude ouverte : le joueur s'est inscrit dans un autre pays que celui du clic. Attend l'opérateur. |
fast_registration | hold | Une alerte de fraude ouverte : le joueur s'est inscrit dans le nombre de secondes fixé après le clic. Attend l'opérateur. |
affiliate_pending | hold | L'affilié n'était pas encore approuvé quand la commission a été gagnée. Une fois l'affilié approuvé, la ligne n'attend plus que sa période de rétention normale. |
affiliate_rejected | hold | La candidature de l'affilié a été rejetée. |
affiliate_suspended | hold | L'affilié était suspendu quand la commission a été gagnée. Une fois l'affilié rétabli, la ligne n'attend plus que sa période de rétention normale. |
chargeback | rejected, approved | Sur une ligne rejetée : un chargeback l'a annulée pendant sa rétention. Sur une ligne d'annulation : elle annule une commission après un chargeback. |
below_threshold | rejected | Une fois les taux disponibles, le premier dépôt admissible ou les dépôts cumulés nets étaient sous le minimum du deal. |
fraud | rejected, approved | L'opérateur a confirmé l'alerte de fraude qui retenait la ligne, ou a retiré la commission pour fraude. |
base_rejected | rejected | Un complément de palier dont la commission a été rejetée alors que les deux étaient en rétention. |
self_excluded | rejected, approved | L'opérateur a retiré la commission : le joueur s'est auto-exclu. Sur une ligne rejetée, la commission n'était pas encore dans un paiement ; sur une ligne d'annulation, elle l'était. |
duplicate_account | rejected, approved | L'opérateur a retiré la commission : le joueur a un autre compte. |
bonus_abuse | rejected, approved | L'opérateur a retiré la commission pour abus de bonus. |
terms_breach | rejected, approved | L'opérateur a retiré la commission pour manquement aux conditions du programme. |
test_account | rejected, approved | L'opérateur a retiré la commission : le joueur était un compte de test. |
other | rejected, approved | L'opérateur a retiré la commission pour une autre raison, écrite dans status_note. |
Statuts des paiements
Un mois se clôture en un lot de paiement, avec un élément par affilié et par devise. Les lots et les éléments se traitent dans le portail ; l'API montre leur résultat par le statut paid des lignes de commission.
| Statut du lot | Signification |
|---|---|
draft | Le mois a été clôturé. L'opérateur examine les éléments. |
approved | Verrouillé. Avec la facturation activée, chaque élément payable reçoit un numéro de facture. Le fichier bancaire (CSV) peut être téléchargé et les éléments payés. |
paid | Tous les éléments à payer ont été marqués comme payés. |
| Statut de l'élément | Signification |
|---|---|
payable | À payer dans ce lot. |
carried | Inférieur au paiement minimum, ou pas supérieur à zéro : reporté au lot suivant. |
held | L'affilié a une alerte de fraude ouverte, ou le programme retient les paiements jusqu'à la vérification d'identité et celle-ci n'est pas encore enregistrée. Le portail indique laquelle. L'opérateur peut libérer l'élément, et enregistrer la vérification d'identité le libère. |
no_details | L'affilié n'a pas saisi ses coordonnées de paiement. Absent du fichier bancaire. |
written_off | Le mois s'est terminé sous zéro et le deal de l'affilié ne reporte pas les mois négatifs : le solde est passé en perte à la clôture et rien n'est reporté sur le lot suivant. Avec un plafond, l'élément est carried et enregistre la partie au-delà du plafond comme passée en perte. |
paid | Marqué comme payé. Ses lignes de commission sont paid, et le tracker de l'affilié est informé. |
Pourquoi une ligne de fichier est refusée
Une ligne refusée est comptée dans rejected, listée dans problems sous la forme line N: reason, et conservée dans le journal des entrées avec la ligne elle-même. En plus des raisons pour lesquelles un événement peut être refusé :
- La ligne n’est pas un CSV valide.
- REG :
registration_dateouplayer_idmanque ou est illisible. - SALES :
activitydateouplayer_idmanque ou est illisible. - SALES, revenu : le joueur n’est pas inscrit.
- SALES, montants : un montant est négatif, illisible ou comporte trop de décimales pour sa devise.
- SALES : le premier dépôt dépasse le total brut des dépôts.
- SALES : un jour accepté est réexporté avec des totaux monétaires, une devise ou des limites horaires modifiés.
- SALES : les dépôts ou chargebacks individuels connus dépassent le récapitulatif du jour.
- SALES : les données du premier dépôt contredisent un autre jour ou une transaction connue.
- SALES : un chargeback agrégé est ambigu pour le CPA sur premier dépôt d’un joueur déjà inscrit.
Résultats dans le journal des entrées
| Statut | Signification |
|---|---|
accepted | Enregistré, avec ce qu'il a produit. |
duplicate | Déjà enregistré ; la première réponse a été renvoyée. |
rejected | Refusé ; le détail indique quel champ et pourquoi. |
bad_signature | Le timestamp ou la signature était incorrect. |
test | Un événement de test depuis la page Intégration. Il suit le vrai parcours et n'enregistre rien. |
États d'un envoi de postback
| Statut | Signification |
|---|---|
queued | En attente de son premier essai, ou du prochain nouvel essai. Le portail l'affiche comme en attente ou en nouvel essai. |
delivered | Le tracker a répondu par un statut 2xx. |
dead | Tous les nouveaux essais ont échoué. Le portail l'affiche comme abandonné ; l'affilié peut le relancer à la main. |
Statuts d'un affilié
| Statut | Signification |
|---|---|
pending | A candidaté ; l'opérateur n'a pas encore décidé. |
approved | Actif dans le programme. |
rejected | La candidature a été refusée. |
suspended | Arrêté par l'opérateur. |
Le lien de tracking
Un lien de tracking est ouvert par un visiteur, pas appelé par votre plateforme. Il enregistre le clic et répond par une redirection 302 vers la landing page de la marque. Tant que la marque n'a pas vérifié son site, le visiteur voit d'abord une courte page indiquant où mène le lien. L'hôte de destination vient des réglages de la marque ; un lien ne peut choisir qu'un chemin sur celui-ci.
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 Paramètres sur le lien
| Paramètre | Signification |
|---|---|
sub1 … sub5 | Les valeurs propres à l'affilié, enregistrées avec le clic et renvoyées dans les postbacks. Une valeur dans l'adresse remplace celle fixée sur le lien. |
utm_source utm_medium utm_campaign utm_term utm_content | Enregistrés avec le clic et transmis à la landing page. Une valeur dans l'adresse remplace celle fixée sur le lien. |
gclid fbclid ttclid msclkid wbraid | Click IDs des régies publicitaires. Enregistrés avec le clic ; disponibles comme macros de postback. Non transmis. |
Paramètres ajoutés à l'URL d'arrivée
| Paramètre | Signification |
|---|---|
cid | Le click ID : 26 caractères en base32 de Crockford (chiffres et lettres majuscules sans I, L, O, U). Il se trie par ordre chronologique. Stockez-le comme du texte. |
btag | <numéro d'affilié>_<numéro de lien> : un à neuf chiffres, un tiret bas, un à neuf chiffres. |
utm_source … utm_content | Les tags UTM du clic, quand ils ne sont pas vides. |
- Si l'URL d'arrivée de la marque contient
{click_id}dans sa query, le click ID y est placé etcidn'est pas ajouté. - Un clic sur le lien d'un affilié qui n'est pas approuvé est enregistré et signalé, et arrive sans
cidnibtag: il ne peut pas être attribué. - Les bots, les aperçus de liens, les requêtes
HEAD, les requêtes sans user agent et les clics répétés dans l'heure sont enregistrés et signalés, pas écartés. Les rapports les excluent. - Les autres paramètres du lien ne sont ni enregistrés ni transmis.
- Un lien auquel l'affilié a donné un nom court répond aussi à
/go/<name>, exactement comme à/c/<code>. Une marque qui a son propre domaine de tracking vérifié sert aussi les deux chemins sur ce domaine. - Un code inconnu reçoit un
404et une page d'erreur HTML, tout comme un lien dont la marque n'a pas encore défini de destination.
Postbacks vers les trackers des affiliés
Cette partie ne demande aucun travail à l'opérateur. Chaque affilié ajoute jusqu'à 10 destinations dans son portail : un modèle d'adresse avec des macros, et les événements dont il veut être informé. Quand un événement est enregistré pour l'un des joueurs de l'affilié, RevRake complète le modèle et l'appelle par une requête GET.
Événements
| Événement | {status} | Quand |
|---|---|---|
registration | lead | Un joueur a été attribué à l'affilié. |
ftd | sale | Un premier dépôt a rapporté une commission CPA à l'affilié. |
commission_approved | approved | Une commission a été approuvée à la fin de sa période de rétention. |
commission_rejected | rejected | Une commission en rétention a été rejetée après examen. |
commission_paid | paid | Une commission a été payée dans un lot de paiement. |
chargeback | rejected | Un chargeback a repris une commission. |
Mots de statut par preset
Une destination créée à partir d'un preset envoie, dans {status}, les mots que son tracker connaît. Les presets de Voluum, PeerClick et FunnelFlux Pro, ainsi que « Other / custom », envoient les mots du tableau ci-dessus. Les mots suivent le preset que porte la destination ; son adresse enregistrée n'est jamais modifiée.
| Événement | Keitaro | Binom | RedTrack | BeMob |
|---|---|---|---|---|
registration | lead | lead | other | new |
ftd | sale | sale | pending | approved |
commission_approved | sale | sale | approved | approved |
commission_rejected | rejected | reject | declined | declined |
commission_paid | sale | sale | approved | approved |
chargeback | rejected | reject | declined | chargeback |
Macros
Une macro est un nom entre accolades. Elle est remplacée par sa valeur, encodée pour l'URL. Les noms sont comparés sans tenir compte de la casse. Un nom que RevRake ne connaît pas est envoyé tel quel, de sorte qu'une faute de frappe apparaît dans le journal des envois. Une valeur qui n'est pas connue est vide.
| Macro | Signification |
|---|---|
{click_id} | Le click ID de RevRake (le cid de l'URL d'arrivée). Vide quand le joueur a été attribué par le btag seul. |
{sub1} … {sub5} | sub1 à sub5 du clic. sub1 porte généralement le click ID du tracker de l'affilié. |
{event} | Le nom de l'événement, comme dans le tableau ci-dessus. |
{status} | Le mot que les trackers emploient pour l'événement, comme dans le tableau ci-dessus, ou le mot propre au tracker pour une destination créée à partir d'un preset (voir le tableau suivant). |
{event_id} | Différent pour chaque événement et stable d'un nouvel essai à l'autre. |
{conversion_id} | Le même pour tous les événements concernant une même commission : ftd, commission_approved, commission_rejected, commission_paid et chargeback. Une inscription a le sien. Utilisez-le comme identifiant de transaction dans un tracker qui met à jour une conversion arrivant de nouveau sous le même identifiant, afin que le revenu soit compté une seule fois. |
{player_id} {affiliate_id} {brand_id} {link_id} | L'identifiant du joueur chez l'opérateur, le numéro d'affilié, le programme et le numéro de lien. |
{campaign} | Le libellé de campagne du lien. |
{commission} {commission_minor} | La commission, en décimal (40.00) ou en unités mineures (4000). Vide pour une inscription, 0 pour une commission rejetée, négative pour un chargeback. |
{amount} {amount_minor} | Le dépôt ou le revenu à l'origine de la commission, en décimal ou en unités mineures, dans la devise où il a été fait. Vide pour une inscription. |
{amount_currency} | Le code ISO de la devise du dépôt. Vide pour une inscription. |
{commission_currency} | Le code ISO de la devise de la commission : celle du deal. Vide pour une inscription. |
{currency} | Le code ISO de l'argent dont parle le postback : la devise de la commission quand il y a une commission, sinon celle du dépôt, sinon la devise de reporting de l'espace de travail. |
{occurred_at} {occurred_at_unix} | Quand cela s'est produit, au format RFC 3339 ou en secondes Unix. |
{country} {device} {os} {browser} {referer} | Ce que l'on sait du clic : pays, type d'appareil, système d'exploitation, navigateur, référent. |
{utm_source} {utm_medium} {utm_campaign} {utm_term} {utm_content} | Les tags UTM du clic. |
{gclid} {fbclid} {ttclid} {msclkid} {wbraid} | Les click IDs des régies publicitaires, quand le clic les portait. |
Autres noms pour les mêmes macros
Les trackers emploient des noms différents pour les mêmes choses. Ceux-ci sont aussi acceptés :
{subid} | = {sub1} |
{clickid} | = {click_id} |
{payout} | = {commission} |
{txid} | = {event_id} |
{transaction_id} | = {event_id} |
Presets
Le portail affilié fournit ces modèles. L'affilié remplace l'hôte par celui de son tracker. Chacun suit la documentation de son tracker : {conversion_id} est dans le paramètre de transaction là où le tracker met à jour une conversion qui arrive de nouveau sous le même identifiant, {event_id} là où il écarterait les événements ultérieurs.
| Keitaro | https://YOUR-TRACKER-DOMAIN/POSTBACK-KEY/postback?subid={sub1}&status={status}&payout={commission}¤cy={currency}&tid={conversion_id} |
| Binom | https://YOUR-TRACKER-DOMAIN/click?cnv_id={sub1}&payout={commission}&cnv_status={status}&cnv_currency={currency} |
| Voluum | https://YOUR-TRACKER-DOMAIN/postback?cid={sub1}&payout={commission}¤cy={currency}&txid={event_id}&et={event} |
| RedTrack | https://YOUR-TRACKER-DOMAIN/postback?clickid={sub1}&sum={commission}&status={status}&type={event}&rdtk_event_id={event_id} |
| BeMob | https://YOUR-TRACKER-DOMAIN/postback?cid={sub1}&payout={commission}&txid={conversion_id}&status={status} |
| PeerClick | https://YOUR-TRACKER-DOMAIN/postback?cid={sub1}&payout={commission}&txid={conversion_id}&status={status}¤cy={currency} |
| FunnelFlux Pro | https://YOUR-TRACKER-DOMAIN/pb/?hit={sub1}&tx={conversion_id}&rev={commission}&status={status} |
Un exemple
https://YOUR-TRACKER-DOMAIN/postback?click_id={sub1}&event={event}&status={status}&payout={commission}¤cy={currency}&tid={conversion_id}&eid={event_id} GET https://tracker.example/postback?click_id=TRACKER_CLICK_ID&event=ftd&status=sale&payout=40.00¤cy=KES&tid=0199b2c9-0a11-7c3e-9f20-7d4b1e6a2c58&eid=0199b2c9-03aa-7e10-b6d2-91c07f5e2a18%3Aftd Envoi
- Un postback est mis en file d'attente dans la même transaction que l'événement qu'il annonce, et envoyé en une dizaine de secondes, le plus ancien d'abord.
- La requête est un
GETavec le user agentRevRake-Postback/1. Elle suit trois redirections au plus et abandonne après 5 secondes. Les certificats sont vérifiés. - Une réponse
2xxest un succès. Toute autre réponse est un échec, retenté après 1 minute, 5 minutes, 25 minutes, 2 heures, 10 heures et 24 heures. - Après le dernier essai, l'envoi est marqué comme abandonné. L'affilié peut le relancer à la main.
- Chaque tentative est enregistrée avec sa durée, le statut et les 500 premiers caractères de la réponse.
- Après 5 puis 15 échecs d'affilée, le propriétaire de la destination reçoit un e-mail. À 20, la destination est désactivée. Ses envois, y compris ceux des événements qui surviennent pendant qu'elle est désactivée, continuent d'être mis en file d'attente et sont envoyés quand l'affilié la réactive. Une destination que l'affilié a désactivée lui-même ne reçoit rien de nouveau.
- RevRake n'appelle que des adresses publiques. Les adresses de bouclage, privées, link-local et de NAT opérateur (CGNAT) sont refusées au moment de la connexion, de sorte qu'une redirection ne peut pas contourner ce contrôle.
- Le modèle doit être une adresse
http://ouhttps://complète de 2 000 caractères au plus.
Pourquoi une tentative a échoué
timeout | Aucune réponse en 5 secondes. |
dns | Le nom d'hôte est introuvable. |
refused | La connexion a été refusée. |
blocked_address | L'adresse est privée ou locale. |
tls | Un problème de certificat. |
too_many_redirects | Plus de trois redirections. |
http_error | Le tracker a répondu par un statut autre que 2xx. |
other | La connexion a échoué pour une autre raison. |
Webhooks opérateur
Les webhooks informent les propres systèmes de l'opérateur (un CRM, un entrepôt de données, un canal de discussion) de ce qui se passe dans le programme. Un admin de l'espace de travail ajoute un endpoint sur la page Intégration du portail opérateur : l'adresse sur votre serveur, les événements à envoyer et une description facultative. Pour chacun de ces événements, RevRake envoie un POST JSON signé à cette adresse. Les autres membres de l'équipe ne peuvent ni voir ni modifier les endpoints.
L'adresse est une adresse https:// complète sur un hôte public (http:// est accepté, mais utilisez https://). Chaque endpoint a son propre secret, qui commence par whsec_. Il n'est affiché qu'une fois, quand l'endpoint est créé ou que son secret est renouvelé : copiez-le à ce moment-là. Le renouvellement crée un nouveau secret immédiatement, et l'ancien cesse de signer.
Un endpoint peut aussi être un canal Slack ou Microsoft Teams : choisissez « Message Slack » ou « Message Microsoft Teams » et collez l'adresse de webhook entrant du canal (pour Teams, un flux « Quand une requête webhook Teams est reçue »). Chaque événement arrive alors en une phrase dans le canal au lieu du JSON signé, et un montant peut ne garder que les premiers dépôts à partir de cette taille.
Événements
Cochez-en un ou plusieurs par endpoint. Les champs de data sont décrits plus bas ; un champ qui ne s'applique pas est omis.
| Événement | Champs de data | Quand |
|---|---|---|
affiliate.applied | affiliate_number affiliate_name email promotes_on traffic | Quelqu'un a postulé sur la page de votre programme ou via un lien d'invitation propre à un deal. Il est envoyé au moment de la candidature, ce qui peut être avant que le candidat ait confirmé son email. Un affilié que vous ajoutez et invitez vous-même envoie affiliate.approved à la place. |
affiliate.approved | affiliate_number affiliate_name email reason decided_by invited | Vous avez approuvé un affilié : une nouvelle candidature, ou un affilié que vous aviez refusé ou suspendu. Un affilié que vous ajoutez et invitez vous-même est approuvé immédiatement et envoie cet événement avec invited à true. |
affiliate.rejected | affiliate_number affiliate_name email reason decided_by | Vous avez refusé une candidature. |
affiliate.suspended | affiliate_number affiliate_name email reason decided_by | Vous avez suspendu un affilié approuvé. |
player.registered | player_id occurred_at attributed affiliate_number affiliate_name attribution_reason | Un joueur a été inscrit, par un événement signé ou une ligne d'un fichier REG, attribué ou non. Une fois par joueur. |
commission.created | player_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currency | Une ligne de commission a été créée : un CPA admissible selon la base du deal, premier dépôt ou dépôts cumulés, ou une part de revenu ou un ajustement du revenu net déclaré. Les compléments de palier et les annulations n’envoient pas cet événement. |
commission.approved | player_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currency | Une commission en rétention a été approuvée parce que sa période de rétention est terminée, compléments de palier compris. Une ligne approuvée dès le départ n'en envoie pas. |
commission.rejected | player_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currency | Une commission en rétention a été refusée parce que vous avez confirmé l'alerte de fraude qui la retenait. commission vaut zéro. Un CPA annulé par un chargeback envoie commission.reversed à la place. |
commission.paid | player_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currency | Une ligne de commission a été payée : un événement par ligne d'un élément de paiement marqué comme payé, lignes d'annulation et de palier comprises. |
commission.reversed | player_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currency | Un chargeback a repris un CPA : annulé pendant la rétention, ou contrepassé par une nouvelle ligne après avoir été approuvé ou payé. commission_id désigne le CPA, commission est son opposé et amount est le dépôt qui a fait l'objet du chargeback. |
payout.batch_closed | batch_id period reference items payable_by_currency closed_by_hand | Un mois a été clôturé en un lot de paiement brouillon, par une personne ou par la clôture programmée. |
payout.batch_approved | batch_id | Un lot de paiement brouillon a été approuvé et verrouillé. |
payout.paid | batch_id item_id affiliate_number affiliate_name currency amount | Un élément d'un lot approuvé a été marqué comme payé. Un lot dont tous les éléments sont payés n'envoie pas d'événement propre. |
tracking.health_alert | brand kind since quiet_hours clicks_at_least | Les liens d'une marque ont reçu au moins le nombre de clics fixé pendant les heures fixées et aucune inscription n'est arrivée (page Intégration, Santé du suivi). Envoyé une fois ; vérifié toutes les heures. |
tracking.health_cleared | brand raised_at cleared_at | La première inscription après une alerte de santé du suivi est arrivée, et l'alerte est levée. |
flag.raised | kind detail affiliate_number affiliate_name | Un nouveau signalement de fraude a été créé sur un affilié (par une règle, un premier dépôt répété ou un auto-parrainage). Les signalements de rafales de clics sont seulement sur la page Signalements. |
postback.destination_off | destination failures affiliate_number affiliate_name | La destination de postbacks d'un affilié a été désactivée après les échecs de livraison consécutifs que permet l'échelle de relances. |
file.late | source date | Un fichier quotidien récupéré selon un horaire n'était pas arrivé trois heures après son heure. Une fois par fichier et par jour. |
webhook.test | message | Uniquement depuis le bouton « Envoyer un test ». Il ne peut pas être coché, n'est pas réessayé et n'apparaît pas dans le journal des envois. |
Le corps
Chaque requête transporte un objet JSON :
| Champ | Type | Signification |
|---|---|---|
id | string | L'identifiant de l'événement, un UUID. Le même pour chaque endpoint qui reçoit l'événement et à chaque nouvel essai : utilisez-le pour écarter les doublons. |
type | string | L'événement, comme dans le tableau ci-dessus. |
created_at | string | Le moment où l'événement a été mis en file, au format RFC 3339 en UTC, avec des fractions de seconde. |
data | object | Les faits de l'événement. Voir les champs ci-dessous. |
{
"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"
}
} Les clés peuvent arriver dans n'importe quel ordre, et l'espacement du JSON n'est pas fixe. Vérifiez les octets tels que reçus, puis analysez-les.
En-têtes
| En-tête | Valeur |
|---|---|
RevRake-Event | L'événement, le même que type dans le corps. |
RevRake-Delivery | L'identifiant de cet envoi vers cet endpoint, un UUID. Le même à chaque nouvel essai, et quand un envoi est renvoyé à la main. |
RevRake-Timestamp | Le moment où cette tentative a été envoyée, en secondes Unix. Nouveau à chaque tentative. |
RevRake-Signature | Le HMAC-SHA256 en hexadécimal minuscule, sous le secret de l'endpoint, de <timestamp>.<raw body>. Nouvelle à chaque tentative. |
La requête porte aussi Content-Type: application/json et l'agent utilisateur 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>"> Les champs de data
| Champ | Type | Signification |
|---|---|---|
affiliate_number | integer | Le numéro de l'affilié. |
affiliate_name | string | Le nom de l'affilié. |
email | string | L'adresse email avec laquelle l'affilié se connecte. |
promotes_on | string | Ce que le candidat a écrit sur les endroits où il fait sa promotion. |
traffic | array of string | Les sources de trafic cochées par le candidat : seo, telegram, paid_social, youtube, email ou offline. |
reason | string | La raison donnée à l'affilié. Toujours présente pour un refus ou une suspension ; peut être vide pour une approbation. |
decided_by | string | L'adresse email du membre de l'équipe qui a décidé, ou qui a ajouté l'affilié. |
invited | boolean | true quand vous avez ajouté et invité l'affilié vous-même, sans candidature. Absent sinon. |
player_id | string | Votre identifiant du joueur. |
occurred_at | string | Le moment où cela s'est produit, au format RFC 3339 : l'inscription, le dépôt, la fin de la période de revenu ou le chargeback. Pour une approbation, un refus ou un paiement : le moment du changement. |
attributed | boolean | Si le joueur appartient à un affilié. Toujours true pour une commission. |
attribution_reason | string | Pourquoi le joueur a été attribué ou non : l'une des raisons d'attribution. |
commission_id | string | L'identifiant RevRake de la ligne de commission : l'id de la ligne dans GET /v1/commissions. Le même dans chaque événement concernant cette commission. |
commission_type | string | Le type de la ligne de commission : cpa, revshare, adjustment ou tier, et reversal pour une ligne d'annulation dans commission.paid. Dans commission.reversed, le type du CPA repris. |
amount | string | Pour une commission : le dépôt ou le revenu net qui la sous-tend, en décimal, dans sa propre devise. Pour payout.paid : le montant de l'élément, en décimal. |
amount_currency | string | Le code ISO de la devise de amount. |
commission | string | La commission, en décimal dans la devise du deal (40.00). Négative pour une annulation, un ajustement à la baisse et une période gagnée par le joueur. |
commission_currency | string | Le code ISO de la devise de la commission : celle du deal. |
batch_id | string | L'identifiant RevRake du lot de paiement, un UUID. |
period | string | Le mois que le lot clôture, YYYY-MM. |
reference | string | La référence du lot, celle du fichier bancaire, par exemple po_2026-09_demo. |
items | integer | Le nombre d'éléments du lot, quel que soit leur statut. |
payable_by_currency | object | Par devise, la somme des montants de tous les éléments, en décimal (1250.00), quel que soit leur statut, éléments reportés compris. |
closed_by_hand | boolean | true quand une personne a clôturé le mois, false pour la clôture programmée. |
item_id | string | L'identifiant RevRake de l'élément de paiement, un UUID. |
currency | string | La devise de l'élément. |
message | string | Une phrase indiquant que le test est arrivé. |
Vérifier une requête
- Lisez le corps brut en octets, avant toute analyse JSON.
- Vérifiez que
RevRake-Timestampest à moins de 5 minutes de votre horloge, et refusez la requête sinon, afin qu'une requête enregistrée ne puisse pas être rejouée plus tard. - Calculez le HMAC-SHA256 en hexadécimal du timestamp, d'un point et du corps brut sous le secret de l'endpoint, et comparez-le à
RevRake-Signatureen temps constant. - Seulement ensuite, analysez le corps. Si vous avez déjà traité son
id, répondez2xxet ne faites rien. - Répondez par n'importe quel
2xxen moins de 5 secondes, et faites le travail lent ensuite.
La même vérification en Node.js et en Python, telle que la page Intégration l'affiche :
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", "")) Envoi, nouveaux essais et désactivation
- Un envoi est mis en file dans la même transaction que le changement qu'il signale : un événement est envoyé si et seulement si le changement a été enregistré. Il est envoyé en une dizaine de secondes environ, le plus ancien d'abord.
- L'envoi est « au moins une fois » : le même événement peut arriver plus d'une fois, par exemple quand votre réponse se perd en route. Écartez les doublons grâce à l'
iddu corps. - L'ordre n'est pas garanti : un nouvel essai peut arriver après un événement plus récent. Ordonnez les événements par
created_atouoccurred_at, pas par leur heure d'arrivée. - Une réponse
2xxen moins de 5 secondes est un succès. Tout le reste est un échec et est réessayé après 1 minute, 5 minutes, 25 minutes, 2 heures, 10 heures et 24 heures, avec le même corps et un nouveau timestamp et une nouvelle signature. - Après le dernier essai, l'envoi est marqué comme abandonné. Un admin peut le renvoyer depuis le journal des envois ; il repart alors pour tout le calendrier de nouveaux essais.
- Après 20 tentatives échouées d'affilée, l'endpoint est désactivé. Ses événements continuent de s'accumuler, et tout ce qui s'est accumulé est envoyé quand un admin le réactive. Aucun email n'est envoyé dans ce cas : l'état de chaque endpoint est visible sur la page Intégration.
- Un endpoint que vous désactivez vous-même ne reçoit rien de nouveau : aucun événement n'est mis en file pour lui tant qu'il est désactivé.
- RevRake n'appelle que des adresses publiques : il abandonne après 5 secondes et vérifie les certificats. Les adresses de bouclage, privées, link-local et de NAT de niveau opérateur sont refusées. Une redirection n'est pas suivie : une réponse
3xxest un échec avec l'erreurredirect, et le journal des envois montre l'adresse vers laquelle elle pointait.
Le tester et lire le journal des envois
- Cliquez sur « Envoyer un test » sur un endpoint : un événement
webhook.testest envoyé immédiatement, signé comme un vrai, et vous voyez le statut répondu par votre endpoint et le temps qu'il a pris. Un test n'est pas réessayé, n'apparaît pas dans le journal des envois et ne compte pas comme un échec. - Le journal des envois d'un endpoint montre ses 100 derniers envois : l'événement, l'état (en attente, nouvel essai, abandonné ou délivré), le nombre de tentatives, le dernier statut ou la dernière erreur, les 500 premiers caractères de votre réponse, le prochain essai, et le corps tel qu'il a été envoyé.
- Une tentative échouée est décrite avec les mêmes mots qu'un postback (voir pourquoi une tentative a échoué), plus
redirect: votre endpoint a répondu par un3xx. Les états sont ceux d'un envoi de postback.
{
"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."
}
} Bonnes pratiques
- Gardez le secret sur votre serveur, jamais dans une page ou une application. S'il fuit, renouvelez-le et passez votre endpoint au nouveau immédiatement : l'ancien secret cesse de fonctionner aussitôt.
- Répondez par un
4xxà une requête dont la signature ne correspond pas. Elle est réessayée, signée avec le secret actuel, donc un envoi fait pendant un renouvellement n'est pas perdu. - Conservez l'
idde chaque événement traité, et ignorez un événement déjà vu. - Répondez d'abord, travaillez ensuite : mettez l'événement dans votre propre file et répondez
2xx, pour qu'une base de données lente ne pousse jamais RevRake à réessayer. - Saisissez l'adresse finale de votre endpoint. Une redirection n'est pas suivie : la tentative échoue avec
redirect, et le journal des envois indique l'adresse à utiliser à la place. - Utilisez
commission_idpour relier les événements concernant une commission, et rapprochez avecGET /v1/commissions: une lecture nocturne des 60 derniers jours rattrape tout ce qui aurait été manqué. - Ne cochez que les événements que vous utilisez. Chacun est une requête vers votre serveur.
Fichier OpenAPI
Les quatre endpoints signés, avec chaque statut et chaque raison sous forme d'énumération, sont décrits dans openapi.yaml (OpenAPI 3.1), pour les générateurs de code et les clients d'API. Son adresse ne change pas.
Prêt à vous connecter ? Créez votre programme et obtenez votre clé.
Vous créez votre programme vous-même : inscrivez-vous, confirmez votre e-mail, et vous y êtes en quelques minutes. Gratuit pour les opérateurs, pour toujours. Sans carte bancaire.
Des questions ? Écrivez à hello@revrake.com