A API da RevRake.
Tudo o que a plataforma de um operador envia à RevRake, o que volta e o que a RevRake envia aos trackers dos afiliados e aos sistemas do próprio operador. Para a ordem em que fazer as coisas, leia o guia de integração.
URLs base
A API tem quatro endpoints assinados para a plataforma do operador, dois de escrita e dois de leitura, e o link de rastreamento que os visitantes abrem. Os endpoints assinados também estão publicados em um arquivo OpenAPI 3.1.
| Endpoint | Significado |
|---|---|
POST https://app.revrake.com/v1/postback | Informa um evento ou um lote de eventos. Assinado. |
POST https://app.revrake.com/v1/files | Envia um arquivo diário REG ou SALES. Assinado. |
GET https://app.revrake.com/v1/reports | Lê um relatório, em JSON ou CSV. Assinado, com uma chave de operador ou de afiliado. |
GET https://app.revrake.com/v1/commissions | Lê o livro-razão de comissões, página por página. Assinado, com uma chave de operador ou de afiliado. |
GET https://app.revrake.com/v1/affiliates | Lista os afiliados da marca. Assinado, com a chave do operador. |
GET https://app.revrake.com/v1/links | Lista os links de rastreamento. Assinado, com uma chave de operador ou de afiliado. |
GET https://app.revrake.com/v1/deals | Lista os acordos com os termos em vigor. Assinado, com a chave do operador. |
GET https://track.revrake.com/c/{code} | O link de rastreamento: grava o clique e redireciona. Não assinado. |
Os portais em app.revrake.com usam seus próprios endpoints, atrás de uma sessão autenticada. Eles não são uma API pública e podem mudar sem aviso. Os relatórios, o livro-razão e as linhas de pagamento também podem ser baixados ali em CSV.
Chaves
Há dois tipos de chave. Cada uma tem um ID de chave e um segredo, e todas assinam as requisições da mesma forma. As chaves nunca são compartilhadas: cada parte tem a sua.
| O ID da chave começa com | De quem é | O que ela pode fazer |
|---|---|---|
pb_ | Do operador. Uma chave ativa por marca, na página Integração do portal do operador. Um admin do workspace pode ver o segredo e rotacionar a chave. | Envia eventos e arquivos. Lê os relatórios e o livro-razão do programa inteiro, ou de um afiliado com affiliate=<number>. |
ak_ | De um afiliado. Cada afiliado cria a sua na aba API do portal do afiliado. O segredo é exibido uma única vez, quando a chave é criada. | Lê os relatórios e as comissões desse afiliado, e nada mais. Não pode enviar eventos: /v1/postback e /v1/files respondem 401 unknown_key. |
Nunca entregue a chave do operador a um afiliado. Ela lê os números de todos os afiliados e pode gravar eventos. Um afiliado que quer acesso à API emite sua própria chave.
- Uma nova chave revoga a antiga imediatamente, nos dois tipos. Um afiliado também pode revogar sua chave e ficar sem nenhuma.
- Uma chave de afiliado só funciona enquanto o afiliado está aprovado no programa. Caso contrário, uma leitura responde
403affiliate_inactive. - Com uma chave de afiliado, o parâmetro
affiliateé ignorado eby=affiliateé respondido por dia. - O limite de taxa das leituras é contado por chave.
Autenticação
Toda requisição a /v1 é assinada com uma chave. Cada requisição leva três cabeçalhos:
| Cabeçalho | Valor |
|---|---|
X-RevRake-Key | O ID da sua chave. Começa com pb_ (operador) ou ak_ (afiliado). |
X-RevRake-Timestamp | O horário Unix atual em segundos. Uma requisição é aceita em até cinco minutos antes ou depois dele. |
X-RevRake-Signature | O HMAC-SHA256 em hexadecimal minúsculo, com o seu segredo, de <timestamp>.<body> para um POST e de <timestamp>.<path>?<query> para um GET. |
Para assinar uma requisição:
- Monte o corpo e guarde os bytes exatos que você vai enviar.
- Pegue o horário Unix atual em segundos, como texto decimal.
- Concatene o timestamp, um ponto (
.) e o corpo. - Calcule o HMAC-SHA256 desse texto com o seu segredo e escreva-o em hexadecimal minúsculo.
- Envie o corpo sem alterações, com os três cabeçalhos.
Como assinar uma leitura
Um GET não tem corpo, então a assinatura cobre o alvo da requisição: o caminho e a query exatamente como enviados, por exemplo 1790000000./v1/reports?by=link&days=7. Sem query, é o timestamp, um ponto e o caminho. Monte o endereço uma vez, assine esse texto e envie esse texto: um cliente que reordena ou recodifica a query depois de assinar quebra a assinatura.
- Primeiro verifica-se a chave, depois o timestamp, depois a assinatura.
- O cabeçalho
Content-Typenão é obrigatório. Envieapplication/jsonpara eventos etext/csvpara arquivos. - Uma chave rotacionada para de funcionar imediatamente.
Exemplos de assinatura
Cada exemplo tem uma única função de assinatura, envia um cadastro e depois lê um relatório. Substitua o ID da chave e o segredo pelos seus.
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))
} Vetor de teste
Com estas entradas, seu código deve produzir exatamente estas assinaturas:
- Segredo
- test_secret
- Timestamp
- 1791072000
- Corpo
- {"type":"registration","player_id":"PLR-1001","btag":"1001_1"}
- Assinatura
- 115d8c73c6069d8953a36ca3a68c114da6232e4ba31889fd519d41ab1350a603
- Alvo da requisição de uma leitura
- /v1/reports?by=link&days=7
- Assinatura da leitura
- ed1ed72dd7ddef22c762f63b8919011e7c36c7214b55b72693c5927fb4b911d0
Limites
Estes são todos os limites que o produto aplica hoje a integrações, rastreamento e afiliados, com seus números. Login, redefinição de senha e candidaturas também têm limites contra abuso.
| Limite | Significado |
|---|---|
| 120 | Leituras por chave, por minuto: GET /v1/reports e GET /v1/commissions somados |
| 30 000 | Requisições de eventos por chave, por minuto: POST /v1/postback, até 1.000 de uma vez |
| 60 | Arquivos por chave, por minuto: POST /v1/files, até 10 de uma vez |
| 4 MB | Corpo de POST /v1/postback, um evento ou um lote |
| 32 MB | Corpo de POST /v1/files |
| 1 – 1000 | Eventos em um lote |
| 200 000 | Linhas de dados em um arquivo |
| 300 s | Diferença entre X-RevRake-Timestamp e o horário real, para mais ou para menos |
| 24 h | Até quanto no futuro ts e period podem estar |
| 100 | Tamanho de player_id, em caracteres |
| 200 | Tamanho de txn_id, em caracteres |
| 0 / 2 | Casas decimais de um valor: as da moeda (duas na maioria, nenhuma em moedas como XOF, UGX ou JPY) |
| 1 – 365 | days de um relatório |
| 10, 25, 50, 100, 500, 1000 | per_page do livro-razão: um destes valores |
| 1 – 100 000 | page do livro-razão |
| 100 | Tamanho de q, em caracteres; um texto mais longo é cortado |
| 200 | Tamanho de sub1 a sub5, de cada tag UTM e de cada click ID de anúncio em um link de rastreamento, em caracteres; valores mais longos são cortados |
| 10 | Destinos de postback por afiliado |
| 2000 | Tamanho de um template de endereço de postback, em caracteres |
| 5 s | Tempo que um tracker tem para responder a um postback |
| 50 | Log de entrada exibido no portal: entradas mais recentes dos últimos 7 dias |
| 2000 | Tamanho do endereço de um endpoint de webhook, em caracteres |
| 5 s | Tempo que um endpoint de webhook tem para responder |
| 20 | Tentativas de webhook falhas seguidas antes de o endpoint ser desligado |
| 100 | Entregas por endpoint de webhook exibidas no log de entregas |
| 2 – 40 | Tamanho de um código promocional: letras, dígitos, hifens e sublinhados |
| 32 MB | Tamanho de um arquivo que a RevRake busca no seu endereço |
| 60 s | Tempo que o seu endereço tem para entregar um arquivo buscado |
| 0 – 3600 s | Segundos após o clique para a regra de tempo de cadastro (0 a desativa) |
| 0 – 365 | Dias até que um alerta de fraude aberto se decida sozinho (0 significa nunca) |
| 1 – 200 | Alertas liberados ou confirmados numa única decisão em lote |
| 0 – 10 000 (20) | Cliques por minuto em um link a partir de um endereço antes de o alerta de rajada de cliques ser criado (0 desativa; 20 se você não mudar) |
| 60 + 1 / min | Links de rastreamento que um afiliado pode criar: 60 de uma vez, depois um por minuto. Além disso a resposta é 429 com Retry-After |
| 2 MB | Tamanho de uma imagem de banner enviada pelo portal: PNG, JPEG, GIF ou WebP |
Os dois endpoints de escrita, POST /v1/postback e POST /v1/files, têm limite por chave (veja a tabela). Toda resposta traz X-RateLimit-Limit e X-RateLimit-Remaining; uma recusa é 429 com Retry-After. Envie no ritmo dos seus eventos e use lotes para uma carga retroativa. O link de rastreamento não tem limite de taxa; uma rajada incomum de cliques em um link a partir de um mesmo endereço gera um alerta de fraude e ainda é redirecionada.
O limite de taxa das leituras
- Cada chave pode fazer 120 leituras por minuto. A cota é um balde de 120: uma leitura consome uma unidade, e uma unidade volta a cada meio segundo. Uma chave que ficou parada pode fazer 120 leituras de uma vez; depois disso, duas por segundo.
- Toda resposta de leitura traz
X-RateLimit-Limit(sempre120) eX-RateLimit-Remaining(quantas leituras restam neste momento). - Acima do limite, a resposta é
429rate_limitedcom um cabeçalhoRetry-After: os segundos a esperar. Espere e envie a mesma requisição de novo, assinada com um timestamp novo. - O limite é contado por chave: a chave do operador e a chave de cada afiliado têm sua própria cota.
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."} Como tratar um 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
Informa um evento da plataforma do operador. O corpo é um objeto JSON com um type e os campos desse tipo, ou um array JSON desses objetos (um lote).
POST https://app.revrake.com/v1/postback typeé um destes:registration,deposit,chargeback,ngr.- Um campo que não esteja listado para o tipo é recusado com
422, então um erro de digitação nunca é ignorado em silêncio. tsé o horário do evento no formato RFC 3339 (2026-10-04T08:15:00Z). Se for omitido, usa-se o horário da requisição. Ele precisa trazer um deslocamento UTC (Zou+03:00); um horário sem deslocamento é recusado. Ele não pode estar mais de um dia no futuro.- Um valor é um decimal, como texto JSON ou número JSON:
"25.00"ou25.5. Sem separador de milhar, sem expoente e sem mais casas decimais do que a moeda tem. currencyé um código ISO 4217 de três letras. Minúsculas são aceitas. Se for omitido, usa-se a moeda de relatório do workspace.- Os espaços no início e no fim dos valores de texto são removidos, exceto em
click_idebtag: envie-os exatamente como chegaram à landing page.
registration
Um novo jogador. Envie click_id, btag, promo_code, ou vários deles; sem nenhum, o jogador é registrado como não atribuído. O jogador é atribuído uma única vez, aqui. Resposta: attribution.
{"type":"registration","player_id":"PLR-1001","click_id":"01K6QF3M8Z5T7W9XB2C4D6E8GH","btag":"1001_1"} | Campo | Tipo | Obrigatório | Exemplo | Significado |
|---|---|---|---|---|
player_id | string | sim | "PLR-1001" | Seu ID para o jogador. Até 100 caracteres. É a chave do evento. |
click_id | string | não | "01K6QF3M8Z5T7W9XB2C4D6E8GH" | O cid com que o jogador chegou: 26 caracteres, letras e dígitos; maiúsculas ou minúsculas. |
btag | string | não | "1001_1" | O btag que sua plataforma guardou no jogador: <número do afiliado>_<número do link>, só dígitos. |
promo_code | string | não | "GARAGE50" | O código promocional que o jogador digitou no cadastro. Não diferencia maiúsculas de minúsculas. Ele atribui o jogador apenas quando click_id e btag não o fazem. |
email_hash | string | não | "9f86d081…0f00a08" | SHA-256 do e-mail em minúsculas, em hexadecimal. Usado apenas pela verificação de autoindicação. |
email_domain | string | não | "example.com" | O domínio do e-mail do jogador, a parte depois do @ (example.com). Usado apenas pela regra de e-mail descartável. Envie só o domínio: se chegar um endereço completo, só o domínio fica no jogador, mas o log de entrada ainda mostra a requisição como chegou. |
ip | string | não | "203.0.113.7" | O endereço IP no cadastro. Ele é convertido em hash e usado apenas pela verificação de autoindicação e para encontrar o clique correspondente a um btag. |
country | string | não | "KE" | O país do jogador: duas letras, ISO 3166-1 alpha-2 (GB, KE). Minúsculas são aceitas. Um valor que não tem duas letras deixa o jogador sem país. Sem o campo, vale o país do clique que trouxe o jogador. Um deal pode listar países pelos quais não paga. |
ts | string | não | "2026-10-04T08:15:00Z" | Quando o jogador se cadastrou. A janela de atribuição é medida a partir dele. |
{
"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
Envie um evento deposit para cada depósito, com seu ID de transação em txn_id. O deal define se o mínimo para CPA é comparado ao primeiro depósito ou aos depósitos acumulados, descontados os chargebacks. A qualificação cria uma comissão CPA por jogador, em retenção.
{"type":"deposit","player_id":"PLR-1001","txn_id":"TX-88213","amount":"25.00","currency":"KES","first":true} | Campo | Tipo | Obrigatório | Exemplo | Significado |
|---|---|---|---|---|
player_id | string | sim | "PLR-1001" | Seu ID para o jogador. Até 100 caracteres. |
txn_id | string | sim | "TX-88213" | Seu ID de transação. Até 200 caracteres. É a chave do evento. |
amount | string | number | sim | "25.00" | O depósito, acima de zero. |
currency | string | não | "KES" | A moeda do depósito. Qualquer moeda é aceita. |
ts | string | não | "2026-10-04T08:20:00Z" | Quando o depósito foi feito. Ele decide qual versão do deal e a taxa de câmbio de qual dia se aplicam. |
first | boolean | não | true | true se este é o primeiro depósito do jogador. Se omitido, o depósito conta como primeiro se a RevRake não conhecer nenhum anterior do jogador. |
{
"status": "accepted",
"event_type": "deposit",
"event_id": "0199b2c9-03aa-7e10-b6d2-91c07f5e2a18",
"commission": {
"effect": "created",
"type": "cpa",
"amount_minor": 4000,
"status": "hold"
}
} chargeback
Envie um evento chargeback com seu próprio txn_id e o txn_id do depósito original em ref_txn_id. Ele reverte o depósito inteiro. No CPA acumulado, a comissão só é retirada se o total qualificado restante ficar abaixo do mínimo: uma comissão em retenção é cancelada; uma aprovada ou paga recebe uma linha de estorno.
{"type":"chargeback","txn_id":"CB-5001","ref_txn_id":"TX-88213"} | Campo | Tipo | Obrigatório | Exemplo | Significado |
|---|---|---|---|---|
txn_id | string | sim | "CB-5001" | Seu ID para o próprio chargeback. Até 200 caracteres. É a chave do evento. |
ref_txn_id | string | sim | "TX-88213" | O txn_id do depósito que sofreu chargeback. |
player_id | string | não | "PLR-1001" | Opcional. Se informado, deve corresponder ao jogador do depósito referenciado. |
ts | string | não | "2026-10-09T11:00:00Z" | Quando o chargeback aconteceu. |
{
"status": "accepted",
"event_type": "chargeback",
"event_id": "0199cc10-7b2d-7c41-a3f0-5d2e8b9c1f47",
"commission": {
"effect": "cancelled",
"type": "cpa",
"amount_minor": 4000,
"status": "rejected"
}
} ngr
A receita líquida de jogo (NGR) de um jogador em um dia ou em um mês. Ela rende o RevShare da versão do deal em vigor no fim do período, em retenção. O jogador precisa estar cadastrado. Resposta: commission.
{"type":"ngr","player_id":"PLR-1001","period":"2026-10-03","amount":"118.40","currency":"KES"} | Campo | Tipo | Obrigatório | Exemplo | Significado |
|---|---|---|---|---|
player_id | string | sim | "PLR-1001" | Seu ID para o jogador. Até 100 caracteres. |
period | string | sim | "2026-10-03" | O dia (YYYY-MM-DD) ou o mês (YYYY-MM) a que o valor se refere. Um mês e o seu primeiro dia são períodos diferentes. Não pode estar mais de um dia no futuro. |
amount | string | number | sim | "118.40" | A receita líquida de jogo (NGR) do período. Negativa quando o jogador ganhou. |
currency | string | não | "KES" | A moeda do valor. |
ggr | string | number | não | "240.00" | Opcional. A receita bruta de jogo do período, na mesma moeda. Mostrada ao afiliado; não altera a comissão. |
bonuses | string | number | não | "80.00" | Opcional. Bônus descontados da receita bruta. Apenas mostrado. |
fees | string | number | não | "21.60" | Opcional. Taxas descontadas da receita bruta, como taxas de pagamento ou de plataforma. Apenas mostrado. |
taxes | string | number | não | "20.00" | Opcional. Impostos descontados da receita bruta. Apenas mostrado. |
ts | string | não | "2026-10-04T02:00:00Z" | Quando o valor foi informado. |
{
"status": "accepted",
"event_type": "ngr",
"event_id": "0199b2d1-5c0e-7b42-8a17-3e9d6f0c4b21",
"commission": {
"effect": "created",
"type": "revshare",
"amount_minor": 2960,
"status": "hold"
}
} Um click_id, btag, promo_code ou player_id que contém { ou } é recusado: isso significa que a sua plataforma enviou um placeholder sem preenchê-lo.
A resposta
Um evento que foi gravado, ou que já estava gravado, é respondido com 200 e um objeto JSON. Os campos que não se aplicam são omitidos.
| Campo | Tipo | Significado |
|---|---|---|
status | string | accepted, ou duplicate quando o evento já estava gravado. |
event_type | string | O type que você enviou. |
event_id | string | O ID da RevRake para o evento gravado, um UUID. É o mesmo em toda repetição. |
attribution | object | Para um cadastro: a decisão. |
attribution.attributed | boolean | Se o jogador pertence a um afiliado. |
attribution.reason | string | O motivo. Veja a tabela abaixo. |
attribution.affiliate_number | integer | O afiliado. Só quando atribuído. |
attribution.link_number | integer | O link do afiliado. Só quando atribuído. |
attribution.click_id | string | O clique que correspondeu, quando há um. |
attribution.policy_version | integer | A versão da política de atribuição da marca que decidiu. |
attribution.window_days | integer | A janela de atribuição dessa versão, em dias. |
attribution.model | string | last_click ou first_click: o modelo dessa versão. |
commission | object | Para um depósito, um chargeback e ngr: o que o evento fez no livro-razão. |
commission.effect | string | created, cancelled (uma comissão em retenção foi rejeitada), reversed (uma linha de estorno foi adicionada) ou none. |
commission.type | string | cpa, revshare, adjustment ou reversal. |
commission.amount_minor | integer | O valor em unidades menores da moeda do deal (4000 é 40.00). Negativo para um estorno e para um ajuste para baixo. |
commission.status | string | hold, approved ou rejected. |
commission.reason | string | Por que nada foi criado, quando effect é none. Veja a tabela abaixo. |
waiting_for_player | boolean | true para um depósito cujo jogador ainda não está cadastrado. Ele é guardado e precificado quando o cadastro chegar. |
duplicate_of | string | Para uma correspondência antiga de primeiro depósito entre eventos ao vivo e arquivos diários antigos: o event_id anterior. Os resumos SALES atuais usam cobertura diária e preservam cada ID de transação real. |
detail | string | Com duplicate_of: uma frase dizendo qual depósito anterior este repete. |
{
"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" }
} Uma comissão é criada com o status hold. Ela é aprovada automaticamente quando o período de retenção do deal termina, a menos que algo ainda a retenha: um alerta de fraude aberto, um afiliado que não está aprovado ou uma taxa de câmbio ausente.
Motivos de atribuição
Primeiro tenta-se o click ID. Se ele não é um dos seus, tenta-se o btag. Quando a política diz que o btag vale e o btag corresponde a um link, o btag é tentado primeiro. Um btag que corresponde a um link atribui o jogador mesmo quando nenhum clique é encontrado. Um código promocional é tentado por último, só quando nem o click ID nem o btag atribuíram o jogador. A política, a janela e qual dos dois vale são definidas na página Integração; cada mudança é uma nova versão. Quando a política diz que vale o código promocional, um código que corresponde a um link é tentado antes dos dois, e um que não corresponde volta para eles. Um acordo pode definir sua própria janela, que substitui a da política para cliques nos links dos seus afiliados.
reason | Significado | |
|---|---|---|
click | Atribuído | O click ID correspondeu a um clique dentro da janela. |
first_click | Atribuído | A política é primeiro clique: o click ID correspondeu a um clique dentro da janela, e um clique contado anterior do mesmo visitante (mesmo endereço e dispositivo) dentro da janela foi creditado no lugar dele. |
btag_click | Atribuído | O btag correspondeu a um link, e um clique nesse link foi encontrado dentro da janela. |
btag_only | Atribuído | O btag correspondeu a um link; nenhum clique foi encontrado dentro da janela. |
promo_code | Atribuído | Nem o click ID nem o btag atribuíram o jogador, e o código promocional correspondeu a um código de um afiliado aprovado. |
no_tag | Não atribuído | O cadastro não trazia nem click ID nem btag. |
unknown_click | Não atribuído | O click ID não é um dos seus, e nenhum btag foi enviado. |
unknown_btag | Não atribuído | O btag está malformado ou não corresponde a nenhum link. |
outside_window | Não atribuído | O clique é mais antigo que a janela de atribuição, ou posterior ao cadastro. |
affiliate_inactive | Não atribuído | O afiliado não está aprovado, ou não estava quando o clique foi feito. |
unknown_promo_code | Não atribuído | Só um código promocional foi enviado, e ele não corresponde a nenhum dos seus códigos. |
promo_code_retired | Não atribuído | Só um código promocional foi enviado, e ele foi desativado. |
Por que nenhuma comissão foi criada
commission.reason | Significado |
|---|---|
unattributed | O jogador não pertence a nenhum afiliado. |
not_first | Não é o primeiro depósito do jogador. |
already_earned | O CPA do jogador já foi ganho. Um segundo "primeiro" depósito não paga nada e gera um alerta. |
no_deal_version | O afiliado não tem deal, ou o deal não tinha versão no momento do evento. |
country_blocked | O jogador é de um país pelo qual o deal não paga. O jogador continua registrado e atribuído. |
no_cpa_in_deal | O deal não paga CPA. |
below_threshold | O primeiro depósito ou os depósitos acumulados líquidos estão abaixo do mínimo do deal, conforme sua base de CPA. |
no_commission | Para um chargeback: o depósito não tinha rendido nada. |
no_revshare_in_deal | Para ngr: o deal não paga RevShare. |
fx_rate_missing | Para ngr: ainda não há taxa de câmbio para o período. O informe é gravado e precificado quando existir uma taxa. |
unchanged | Para ngr: um valor corrigido que não muda nada na comissão. |
Lotes
O corpo pode ser um array JSON de 1 a 1.000 eventos, enviado ao mesmo endpoint com os mesmos cabeçalhos. A assinatura cobre o array inteiro. Os eventos são tratados em ordem, cada um separadamente, então um evento recusado nunca interrompe os demais.
Um lote que pôde ser lido é respondido com 200, mesmo quando todos os eventos dele foram recusados. Olhe as contagens.
[
{"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
} | Campo | Tipo | Significado |
|---|---|---|
results | array | Uma entrada por evento, na ordem de envio. |
results[].index | integer | A posição do evento no array, a partir de 0. |
results[].status | string | accepted, duplicate ou rejected. |
results[].event_type | string | Como em uma resposta individual. Não aparece em um evento recusado. |
results[].event_id | string | Como em uma resposta individual. Não aparece em um evento recusado. |
results[].attribution | object | Como em uma resposta individual. |
results[].commission | object | Como em uma resposta individual. |
results[].waiting_for_player | boolean | Como em uma resposta individual. |
results[].field | string | Para um evento recusado: o campo a corrigir. |
results[].message | string | Para um evento recusado: o que corrigir. |
accepted | integer | Quantos eventos foram gravados. |
duplicate | integer | Quantos já estavam gravados. |
rejected | integer | Quantos foram recusados. |
POST /v1/files
Envia um arquivo CSV diário, como alternativa ao envio pela página Integração ou a deixar a RevRake buscá-lo num endereço onde a sua plataforma o publica. O corpo é o próprio arquivo; os cabeçalhos e a assinatura são os de um evento, e a assinatura cobre o timestamp e o arquivo. O nome do arquivo vai no parâmetro de query filename; ele é exibido no portal e não é usado para mais nada.
POST https://app.revrake.com/v1/files?filename=sales-2026-10-03.csv A linha de cabeçalho decide qual arquivo é: um arquivo com uma coluna registration_date é um arquivo REG, um com uma coluna activitydate é um arquivo SALES. Os nomes das colunas são comparados sem diferenciar maiúsculas de minúsculas. Colunas que não estão listadas abaixo podem ficar no arquivo; são ignoradas.
As datas aceitas são YYYY-MM-DD, YYYY-MM-DD HH:MM:SS, YYYY-MM-DDTHH:MM:SS, RFC 3339 ou YYYY/MM/DD. Sem offset UTC, vale o fuso dos arquivos em Configurações do workspace (UTC por padrão). Um timestamp com offset identifica um instante exato; em SALES, usa-se seu dia de calendário no fuso dos arquivos. Dia e mês nunca são adivinhados: 30/09/2026 é recusado.
Arquivo REG: uma linha por jogador cadastrado
| Coluna | Obrigatório | Significado |
|---|---|---|
registration_date | sim | Quando o jogador se cadastrou. Vira ts. |
player_id | sim | Seu ID para o jogador. |
btag | sim | O btag guardado no jogador. Pode ficar vazio: nesse caso o jogador não é atribuído, a menos que um código promocional o atribua. |
promo_code | não | Opcional. O código promocional que o jogador digitou no cadastro, usado como o promo_code de um cadastro. |
player_country | não | Opcional. O código de duas letras do país do jogador (ISO 3166-1 alpha-2), usado como o country de um cadastro. Vazio: o país do clique. |
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 Arquivo SALES: uma linha por jogador por dia
| Coluna | Obrigatório | Significado |
|---|---|---|
activitydate | sim | O dia de atividade, determinado no fuso horário dos arquivos do workspace. |
player_id | sim | Seu ID para o jogador. |
currency | sim | A moeda dos valores da linha. Vazia: a moeda de relatório do workspace. |
deposits | sim | Total bruto de depósitos do dia, incluindo o primeiro depósito ocorrido nesse dia. Não é o total histórico; não desconte chargebacks. |
first_deposit_amount | sim | Valor do primeiro depósito, somente no dia em que ocorreu; zero nos demais dias. Já está incluído em deposits e nunca é somado novamente. Não pode superar o total bruto de depósitos do dia. |
chargeback | sim | Total de chargebacks deste dia de atividade, separado dos depósitos brutos. Não é o total histórico. Reduz os depósitos acumulados para CPA, mas não identifica uma transação específica. |
*_net_revenue | não | Todas as colunas com o nome net_revenue ou terminadas em _net_revenue. As células preenchidas são somadas na receita líquida do jogador naquele dia, informada como ngr. Uma linha sem nenhuma delas preenchida não informa receita. |
*_gross_revenue | não | Opcional. Colunas com o nome gross_revenue ou terminadas em _gross_revenue, somadas no ggr do ngr do dia. Apenas mostrado ao afiliado. |
*_bonus | não | Opcional. Colunas com o nome bonus ou terminadas em _bonus, somadas em bonuses. Apenas mostrado. |
*_fees | não | Opcional. Colunas com o nome fees ou terminadas em _fees, somadas em fees. Apenas mostrado. |
*_taxes | não | Opcional. Colunas com o nome taxes ou terminadas em _taxes, somadas em taxes. Apenas mostrado. |
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, - Cada linha SALES registra um resumo monetário diário e, quando há células de receita preenchidas, um evento NGR separado. São processados independentemente: um resumo monetário recusado não desfaz uma receita aceita, nem o contrário. Confira todos os problemas na resposta.
- Um resumo por marca, jogador e dia de atividade; a primeira moeda aceita fica fixa. Valores monetários idênticos são replays mesmo após renomear ou reordenar o arquivo. Alterar valores, moeda ou limites de fuso horário de um dia aceito é conflito, inclusive ao alterar zeros. O dinheiro já registrado permanece inalterado.
deposits,first_deposit_amountechargebacksão colunas obrigatórias. Células vazias significam zero. Os valores devem ser decimais não negativos com a precisão da moeda da linha. Confirme essas definições com sua plataforma antes de conectar a exportação.- Envie REG antes de SALES. Resumos monetários recebidos antes são guardados e precificados quando o cadastro chega. NGR de jogador desconhecido é recusado: após REG, reenvie SALES ou NGR. O resumo monetário salvo será um replay.
- O resumo cobre postbacks individuais do dia de atividade e da moeda no fuso dos arquivos, sem somar valores duas vezes. Os IDs de transação continuam referenciáveis. Depósitos ou chargebacks conhecidos acima do resumo, ou evidências inconsistentes de primeiro depósito, geram conflito.
- No CPA acumulado, depósitos menos chargebacks devem atingir o mínimo do deal. Cada fluxo diário usa a taxa de câmbio da data de atividade; postbacks individuais usam seu próprio dia UTC. A falta de taxas mantém a liquidação em retenção sob
fx_rate_missing. Taxas de chargeback ausentes bloqueiam o pagamento sobchargeback_fx_missingaté a reconciliação, inclusive para comissões já incluídas em um pagamento. - No CPA de primeiro depósito, um chargeback agregado pode não identificar o depósito revertido. Um resumo monetário ambíguo de jogador já cadastrado é recusado. Se chegou antes de REG, é guardado e o cadastro é aceito, mas o CPA resultante permanece em retenção sob
chargeback_reference_missing. Para revisar a referência da transação, envie um chargeback comref_txn_iddefinido como o ID de transação do depósito original. - A receita é separada dos totais monetários imutáveis: alterar o NGR diário é uma reapresentação, e a diferença de comissão vira um ajuste.
A resposta
Um arquivo legível retorna 200. Os contadores são por evento, não apenas por linha: uma linha SALES pode registrar resumo monetário e NGR separadamente, inclusive com sucesso parcial. Sempre confira rejected e 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."]
} | Campo | Tipo | Significado |
|---|---|---|
id | string | O ID da RevRake para esta importação. |
filename | string | O nome que você informou, ou reg.csv / sales.csv. |
kind | string | reg ou sales. |
uploaded_at | string | Quando foi recebido. |
rows_total | integer | Linhas de dados no arquivo. |
accepted | integer | Eventos gravados. |
duplicates | integer | Eventos que já estavam gravados. |
rejected | integer | Linhas ou eventos recusados. Cada um está no log de entrada com a própria linha. |
skipped | integer | Linhas sem nada a registrar. |
problems | array of string | As primeiras 20 linhas recusadas, no formato line N: reason. Omitido quando não há nenhuma. |
GET /v1/reports
Devolve o relatório da página Relatórios: cliques, cliques sinalizados, cadastros, primeiros depósitos e ganhos, agrupados de uma forma, para os dias até hoje no fuso horário do workspace. Os números de hoje são atualizados quando um relatório é solicitado, no máximo a cada 30 segundos em um programa movimentado.
GET https://app.revrake.com/v1/reports?by=link&days=7 | Parâmetro | Tipo | Exemplo | Significado |
|---|---|---|---|
by | string | link | Como as linhas são agrupadas: day, link, sub1, country ou affiliate. Padrão: day. Com affiliate definido, by=affiliate é respondido como day. |
days | integer | 7 | Quantos dias, contando hoje: de 1 a 365. Padrão: 30. |
from | string | 2026-09-01 | O primeiro dia de qualquer período, YYYY-MM-DD no fuso horário do workspace. Com from ou to, days é ignorado. No máximo 366 dias. |
to | string | 2026-09-30 | O último dia do período, incluído. Padrão: hoje. |
affiliate | integer | 1001 | Um número de afiliado. Restringe o relatório a esse afiliado. Só com chave de operador; ignorado com uma chave de afiliado, que sempre lê o seu próprio afiliado. |
tag | string | Influencers | O nome de um grupo, como na página Grupos (repita para vários: qualquer um deles). Só com a chave do operador; ignorado com affiliate ou com uma chave de afiliado. Um nome desconhecido dá 422 unknown_tag. |
format | string | csv | csv devolve um arquivo CSV em vez 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
}
} | Campo | Tipo | Significado |
|---|---|---|
by | string | O agrupamento que foi usado. |
from | string | O primeiro dia do relatório, YYYY-MM-DD. |
to | string | O último dia: hoje no fuso horário do workspace, ou o to que você informou. |
currency | string | A moeda de relatório do workspace. Os ganhos estão nela. |
rows | array | Uma entrada por grupo. |
rows[].key | string | O que identifica o grupo: o dia, o ID da RevRake para o link ou o afiliado, o valor de sub1 ou o país em duas letras. |
rows[].label | string | O texto que o portal mostra para o grupo: o dia, o rótulo de campanha do link, o valor de sub1, o país, ou o nome e o número do afiliado. |
rows[].clicks | integer | Cliques limpos. |
rows[].flagged_clicks | integer | Cliques sinalizados como bots, repetições, rajadas ou de um afiliado que não está aprovado. Não entram em clicks. |
rows[].registrations | integer | Jogadores atribuídos. |
rows[].ftds | integer | Primeiros depósitos. |
rows[].earnings_minor | integer | Comissões ganhas, em unidades menores da moeda de relatório, pela taxa do dia em que cada uma foi ganha. |
total | object | A soma das linhas, no formato de uma linha. |
Em CSV
Com format=csv a resposta é um arquivo. A primeira coluna leva o nome do agrupamento e contém o rótulo; depois vêm clicks, flagged_clicks, registrations, first_deposits e earnings_<currency> como decimal. A última linha é o 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
Devolve uma página do livro-razão de comissões, das mais recentes para as mais antigas, a menos que você ordene de outra forma. As linhas nunca têm seus valores editados e nunca são apagadas, mas o status de uma linha muda depois que ela é gravada: hold, depois approved, depois paid, ou rejected. Uma sincronização precisa ler um período de novo e atualizar as linhas pelo id, não apenas buscar linhas novas.
GET https://app.revrake.com/v1/commissions?from=2026-09-01&to=2026-10-01&per_page=500 | Parâmetro | Tipo | Exemplo | Significado |
|---|---|---|---|
status | string | approved | hold, approved, paid ou rejected. Padrão: todos. |
from | string | 2026-09-01 | Só linhas ocorridas neste horário ou depois dele: RFC 3339, ou um dia YYYY-MM-DD em UTC. |
to | string | 2026-10-01 | Só linhas ocorridas antes deste horário. Mesmos formatos. |
affiliate | integer | 1001 | Um número de afiliado. Restringe as linhas, totals e owed a esse afiliado. Só com chave de operador; ignorado com uma chave de afiliado. |
tag | string | Influencers | O nome de um grupo, como na página Grupos (repita para vários: qualquer um deles). Só com a chave do operador; ignorado com affiliate ou com uma chave de afiliado. Um nome desconhecido dá 422 unknown_tag. |
q | string | PLR-1001 | Linhas cujo ID do jogador ou nome do afiliado contém este texto. Até 100 caracteres. |
sort | string | when | when, affiliate, player, status, deposit ou commission. Padrão: when. |
dir | string | asc | asc ou desc. Padrão: desc. |
page | integer | 2 | A página, a partir de 1. Padrão: 1. |
per_page | integer | 500 | 10, 25, 50, 100, 500 ou 1000. Padrão: 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
} | Campo | Tipo | Significado |
|---|---|---|
currency | string | A moeda de relatório do workspace. |
totals | object | A soma por status, em unidades menores da moeda de relatório: em todo o livro-razão, ou no período quando from ou to é informado. Não é restringida pelos outros filtros, exceto affiliate. Linhas que ainda aguardam uma taxa de câmbio não entram nela. |
owed | object | A soma por moeda e status, na moeda própria de cada comissão: o que é devido. Sobre as mesmas linhas de totals. |
period | boolean | true quando from ou to foi informado, então totals e owed cobrem apenas esse período. |
commissions | array | As linhas desta página. |
total | integer | Quantas linhas correspondem aos filtros. |
page | integer | A página que foi devolvida. |
per_page | integer | O número de linhas por página que foi usado. |
Uma linha de comissão
| Campo | Tipo | Significado |
|---|---|---|
id | string | O ID da RevRake para a linha, um UUID. Ele nunca muda: atualize por ele. |
occurred_at | string | Quando a comissão foi ganha: o horário do depósito, o fim do período de receita ou o horário do chargeback. |
type | string | cpa, revshare, adjustment, reversal ou tier. |
amount_minor | integer | A comissão, em unidades menores de currency. Negativa para um estorno e para um ajuste para baixo. |
currency | string | A moeda da comissão: a do deal. |
reporting_minor | integer | null | A comissão na moeda de relatório do workspace, pela taxa do dia em que foi ganha. null enquanto essa taxa estiver ausente. |
gross_minor | integer | O depósito ou a receita líquida por trás da comissão, em unidades menores de gross_currency. |
gross_currency | string | A moeda do depósito ou da receita. |
rate_snapshot | integer | Os termos que foram aplicados: o valor do CPA em unidades menores, ou o RevShare em centésimos de um por cento (2500 é 25%). |
status | string | hold, approved, paid ou rejected. Veja os status de comissão. |
status_reason | string | Por que uma linha ainda está em retenção ou foi rejeitada. Vazio nos demais casos. Todos os valores estão na tabela de motivos. |
status_note | string | A nota do operador sobre uma comissão retirada, como o afiliado a lê. Vazia nos outros casos. |
hold_until | string | null | Quando o período de retenção termina. null para um estorno. |
affiliate_number | integer | O número do afiliado. |
affiliate_name | string | O nome do afiliado. |
player_ref | string | Seu ID para o jogador. |
deal_name | string | O deal. |
deal_version | integer | A versão do deal que precificou a linha. |
Listas do programa: afiliados, links, acordos
Seu backend pode listar o programa como o portal mostra, assinado como as outras leituras e contado no mesmo limite. GET /v1/affiliates e GET /v1/deals exigem a chave do operador; com uma chave de afiliado respondem 403 operator_key_required. GET /v1/links responde os links da marca, ou os de um afiliado com affiliate=<número>; com uma chave de afiliado, os do próprio afiliado.
As listas são paginadas com page (a partir de 1) e per_page (de 1 a 500, padrão 100) e trazem total. GET /v1/affiliates aceita também status: pending, approved, rejected ou suspended. Criar afiliados ou links pela API ainda não é oferecido: conte-nos para que você usaria.
GET https://app.revrake.com/v1/links?affiliate=1001&per_page=100 Cada afiliado
| Campo | Tipo | Significado |
|---|---|---|
number | integer | O número do afiliado, a primeira parte do btag; num link, o número do link, a segunda parte. |
name | string | O nome do afiliado. |
email | string | O e-mail do afiliado. |
status | string | pending, approved, rejected ou suspended. |
deal | string | O nome do acordo do afiliado; vazio antes da aprovação. |
created_at | string | Quando foi criado, RFC 3339. |
decided_at | string | null | Quando a inscrição foi aprovada ou recusada, ou a conta suspensa; null antes disso. |
Cada link
| Campo | Tipo | Significado |
|---|---|---|
affiliate_number | integer | O número do afiliado dono do link. |
number | integer | O número do afiliado, a primeira parte do btag; num link, o número do link, a segunda parte. |
code | string | O código no endereço do link. |
url | string | O link de rastreamento, no domínio de rastreamento verificado da marca ou no compartilhado. |
btag | string | <affiliate_number>_<number>. |
campaign | string | O rótulo de campanha do link. |
landing_path | string | null | A página do seu site para onde o link leva; null para a padrão da marca. |
subs | string[5] | sub1 a sub5 fixados no link; textos vazios quando não definidos. |
promo_code | string | null | O código promocional, num link criado para um; senão null. |
vanity_url | string | null | O endereço curto /go/<nome>, quando o afiliado definiu um; senão null. |
created_at | string | Quando foi criado, RFC 3339. |
Cada acordo
| Campo | Tipo | Significado |
|---|---|---|
name | string | O nome do afiliado. |
currency | string | A moeda em que o acordo rende e paga. |
listed | boolean | Se a página pública de inscrição mostra o acordo. |
default | boolean | Se novos afiliados recebem este acordo. |
version | integer | A versão do acordo em vigor agora. |
effective_at | string | Quando essa versão entrou em vigor, RFC 3339. |
terms | object | Os termos dessa versão: valores em unidades menores, percentuais em pontos-base (2500 = 25%), dias de retenção, regra de meses negativos, a janela de atribuição própria do acordo, faixas. |
Exportação para data warehouse
Configurada na página Integração: toda noite o RevRake grava o dia anterior de cada marca no seu próprio bucket, em qualquer serviço compatível com S3, em <pasta>/<marca>/<AAAA-MM-DD>/, com o dia contado no fuso horário do workspace. Quatro arquivos CSV compactados com gzip (UTF-8, linha de cabeçalho, aspas conforme RFC 4180) e depois manifest.json. O manifesto é gravado por último: carregue um dia quando ele existir e confira rows, bytes e sha256 de cada arquivo.
Uma linha pertence ao dia em que chegou (um clique: quando aconteceu), então um arquivo diário que chega atrasado fica no dia em que chegou, nunca se perde. Horários em RFC 3339, UTC com milissegundos; valores em decimais na própria moeda. Os status são os do momento da exportação: o de uma comissão muda depois, então leia GET /v1/commissions de novo para o atual. Um dia com falha é tentado de novo a cada hora e recuperado até sete dias atrás; exportar um dia de novo sobrescreve seus arquivos. Colunas novas podem ser adicionadas no fim de um arquivo; schema_version no manifesto muda quando um carregador precisa mudar.
manifest.json: schema_version, workspace, brand, day, timezone, from e to (os limites do dia em UTC), generated_at e files: para cada um, name, rows, bytes, sha256 (do arquivo compactado).
clicks.csv.gz: todos os cliques nos links da marca naquele dia, inclusive os sinalizados.
| Campo | Tipo | Significado |
|---|---|---|
click_id | string | O ID do clique, como passado à sua página de destino e nos postbacks. |
clicked_at | string | Quando o clique aconteceu. |
affiliate_number | integer | O número do afiliado. |
link_number | integer | O número do link. |
btag | string | <affiliate_number>_<link_number>. |
country | string | Código do país com duas letras; vazio se desconhecido. |
device | string | desktop, mobile, tablet ou bot, pelo navegador. |
os | string | O sistema operacional, pelo navegador. |
browser | string | O navegador. |
sub1 … sub5 | string | sub1 a sub5: os sub-IDs do clique. |
utm_source … utm_content | string | utm_source a utm_content: as tags UTM do clique. |
gclid, fbclid, ttclid, msclkid, wbraid | string | gclid, fbclid, ttclid, msclkid, wbraid: IDs de clique de plataformas de anúncio na URL de destino. |
referer | string | A página de onde o visitante veio. |
flags | string | Por que o clique não conta, separado por ;: bot, duplicate, burst, inactive. Vazio para um clique limpo. |
players.csv.gz: jogadores cujo cadastro chegou naquele dia.
| Campo | Tipo | Significado |
|---|---|---|
player_id | string | Seu ID de jogador. |
registered_at | string | O horário de cadastro que você enviou. |
arrived_at | string | Quando o RevRake o registrou. |
country | string | Código do país com duas letras; vazio se desconhecido. |
attributed | boolean | true quando um afiliado é creditado. |
attribution_reason | string | Por quê, como na resposta do postback: click, btag_only, promo_code, no_tag… |
affiliate_number | integer | O número do afiliado. |
link_number | integer | O número do link. |
btag | string | <affiliate_number>_<link_number>. |
click_id | string | O clique que creditou o jogador; vazio se não houver. |
policy_version | integer | A versão da política de atribuição que decidiu. |
events.csv.gz: todos os eventos aceitos da marca que chegaram nesse dia, incluindo resumos diários SALES, com seu payload.
| Campo | Tipo | Significado |
|---|---|---|
event_id | string | O ID do evento no RevRake. |
type | string | registration, deposit, chargeback, daily_sales ou ngr; para uma comissão, cpa, revshare, tier, adjustment ou reversal. |
external_id | string | A chave do evento: o ID do jogador, o ID da transação, ou jogador e período. |
player_id | string | Seu ID de jogador. |
occurred_at | string | Quando aconteceu, como você enviou; numa comissão, quando foi ganha. |
received_at | string | Quando o RevRake aceitou o evento. |
source | string | s2s (a API) ou file (um arquivo diário). |
payload | JSON | O evento como o RevRake o leu, em JSON. |
result | JSON | O que o RevRake respondeu, em JSON. |
commissions.csv.gz: linhas de comissão gravadas naquele dia.
| Campo | Tipo | Significado |
|---|---|---|
commission_id | string | O ID da linha, o id em GET /v1/commissions. |
created_at | string | Quando a linha foi gravada. |
occurred_at | string | Quando aconteceu, como você enviou; numa comissão, quando foi ganha. |
type | string | registration, deposit, chargeback, daily_sales ou ngr; para uma comissão, cpa, revshare, tier, adjustment ou reversal. |
status | string | hold, approved, paid ou rejected, na exportação. |
status_reason | string | Por que está retida ou rejeitada; vazio caso contrário. |
affiliate_number | integer | O número do afiliado. |
player_id | string | Seu ID de jogador. |
deal | string | O nome do acordo. |
deal_version | integer | A versão do acordo que a precificou. |
gross | decimal | O depósito ou a receita líquida por trás dela. |
gross_currency | string | A moeda dele. |
amount | decimal | A comissão. |
currency | string | A moeda do acordo. |
reporting_amount | decimal | A comissão na moeda de relatórios; vazio enquanto falta a taxa de câmbio. |
reporting_currency | string | A moeda de relatórios do workspace. |
reverses_id | string | Num estorno, a linha estornada. |
payout_item_id | string | A linha de pagamento que a incluiu, quando o mês fechou. |
Idempotência
Cada evento tem uma chave natural. Uma tentativa idêntica retorna a resposta salva com "status":"duplicate". Um depósito aguardando cadastro tem sua resposta atualizada quando o cadastro chega. Fatos monetários alterados podem gerar conflito; reapresentações de NGR usam revisões. Após um timeout, tente novamente com um novo timestamp de assinatura.
| Evento | Chave | A mesma chave de novo |
|---|---|---|
registration | player_id | A primeira resposta. A atribuição não é decidida de novo, mesmo que as tags sejam diferentes. |
deposit | txn_id | A resposta salva, atualizada quando o cadastro pendente chega. Alterar jogador, valor ou moeda gera conflito. Um resumo SALES que cubra a transação não descarta seu ID. |
chargeback | txn_id | A primeira resposta. Um segundo chargeback do mesmo depósito com um novo txn_id é recusado. |
ngr | player_id e period | Mesmo valor e mesma moeda: a primeira resposta. Valor diferente: uma correção, gravada como nova revisão, com a diferença como adjustment. |
| CSV | Linha REG: player_id | Como um registration. |
| CSV | Resumo monetário SALES: marca, jogador e dia de atividade | Totais idênticos são replays. Alterar depósitos, primeiro depósito, chargebacks, moeda ou limites do dia gera conflito, mesmo em um resumo antes zerado. |
| CSV | Linha SALES, receita: o jogador e o dia | Como ngr: um valor alterado em uma reexportação é uma correção. |
Status e erros
Todas as respostas que a API pode dar e todos os status que um registro pode ter, em um só lugar. Um erro é respondido com um objeto JSON: error (o código), message (uma frase em inglês) e, para invalid, field.
{"error":"invalid","field":"amount","message":"amount must be a positive decimal in KES, for example 25.00."} Status HTTP e códigos de erro
| Status | error | Endpoint | Quando | O que fazer |
|---|---|---|---|---|
| 200 | – | /v1/* | A requisição foi tratada. Para um evento: gravado, ou já gravado. Para um lote ou um arquivo: lido; olhe as contagens, alguns itens podem ter sido recusados. | |
| 400 | bad_request | POST /v1/postback | O corpo começa como um array, mas não é um array JSON de eventos. | Corrija a requisição. A mesma requisição de novo recebe a mesma resposta. |
| 401 | unknown_key | /v1/* | A chave em X-RevRake-Key é desconhecida ou foi revogada, ou é uma chave de afiliado em um endpoint de escrita. | Use a chave atual. Enviar de novo não adianta. |
| 401 | bad_timestamp | /v1/* | X-RevRake-Timestamp está ausente, não é um número inteiro de segundos ou está mais de cinco minutos fora do horário real. | Verifique o relógio e o código de assinatura e envie de novo com um timestamp novo. |
| 401 | bad_signature | /v1/* | A assinatura não corresponde ao timestamp e ao corpo (em uma leitura: ao caminho e à query). | Verifique o relógio e o código de assinatura e envie de novo com um timestamp novo. |
| 403 | affiliate_inactive | GET /v1/* | Uma leitura com uma chave de afiliado cujo afiliado não está aprovado no programa: pendente, rejeitado ou suspenso. | Não há nada a corrigir na requisição: a conta precisa ser aprovada pelo operador. |
| 404 | unknown_affiliate | GET /v1/* | Uma leitura com uma chave de operador: nenhum afiliado tem o número informado em affiliate. | Corrija a requisição. A mesma requisição de novo recebe a mesma resposta. |
| 405 | – | /v1/* | O endpoint não aceita esse método. Sem corpo JSON. | Corrija a requisição. A mesma requisição de novo recebe a mesma resposta. |
| 413 | too_large | POST /v1/* | O corpo é maior que o limite do endpoint. | Corrija a requisição. A mesma requisição de novo recebe a mesma resposta. |
| 422 | invalid | POST /v1/*, GET /v1/reports | O evento ou o arquivo não pode ser usado como está. | Corrija a requisição. A mesma requisição de novo recebe a mesma resposta. |
| 429 | rate_limited | GET /v1/* | Mais leituras do que a cota da chave. A resposta traz Retry-After. | Espere os segundos indicados em Retry-After e envie de novo. |
| 500 | internal | /v1/* | Algo deu errado do nosso lado. | Envie de novo. |
- Um lote sem eventos ou com mais de 1.000 é recusado com
422invalide semfield. - Um
401por timestamp ou assinatura incorretos com uma chave de operador aparece no log de entrada comobad_signature. Uma requisição com chave desconhecida, ou com uma chave de afiliado, não é registrada. - Uma leitura responde
422apenas para um período de relatório que não pode ser usado (frometo). Qualquer outro parâmetro com um valor não permitido é ignorado e usa-se o valor padrão. Confiraby,pageeper_pagena resposta. - Reenvie em um timeout, em um
429e em um500. Não reenvie nenhum outro4xxsem alterações.
O que field indica em um 422
field | Quando |
|---|---|
body | O corpo não é JSON válido, ou traz um campo desconhecido ou malformado (por exemplo, um ts que não está em RFC 3339). |
type | type está ausente ou não é um dos quatro. |
player_id | Ausente ou com mais de 100 caracteres; um placeholder que não foi preenchido; para ngr, um jogador que não está cadastrado. |
click_id | Um placeholder que não foi preenchido. A mensagem começa com misconfigured_macro. |
btag | Um placeholder que não foi preenchido. A mensagem começa com misconfigured_macro. |
promo_code | Um placeholder que não foi preenchido. A mensagem começa com misconfigured_macro. |
txn_id | Ausente ou com mais de 200 caracteres. |
ref_txn_id | Ausente; nenhum depósito com esse txn_id é conhecido; ou o depósito já sofreu chargeback. |
amount | Não é um decimal que a moeda permite; para um depósito, não está acima de zero. |
currency | Não é um código de três letras. |
ggr | Para ngr: não é um valor decimal na moeda. |
bonuses | Para ngr: não é um valor decimal na moeda. |
fees | Para ngr: não é um valor decimal na moeda. |
taxes | Para ngr: não é um valor decimal na moeda. |
ts | Mais de um dia no futuro. |
period | Não é um dia nem um mês, ou está no futuro. |
from | Para GET /v1/reports: from ou to não está no formato YYYY-MM-DD, from é posterior a to, ou os dois estão a mais de 366 dias de distância. |
file | Para /v1/files: o arquivo está vazio, não é CSV, não é um arquivo REG nem SALES, não tem uma coluna obrigatória ou tem mais de 200.000 linhas. |
chargeback | Em um arquivo SALES: a célula chargeback não pode ser aplicada. A mensagem diz por quê. |
O status de um evento
Na resposta a um evento, e por evento em results de um lote.
status | Significado |
|---|---|
accepted | Gravado agora. A resposta diz o que ele fez. |
duplicate | Já salvo com a mesma chave; um replay idêntico não altera nada. Uma correspondência antiga de primeiro depósito entre canais também pode retornar duplicate_of. Os resumos SALES atuais mantêm as transações reais dos postbacks e contam os valores diários cobertos apenas uma vez. |
rejected | Só em um lote: o evento foi recusado, com field e message. Um evento individual recusado é um 422. |
O efeito de um evento no livro-razão
commission.effect | Significado |
|---|---|
created | Uma linha de comissão foi criada: um CPA, um RevShare ou um ajuste por um valor corrigido. |
cancelled | Um chargeback rejeitou uma comissão que ainda estava em retenção. |
reversed | Um chargeback adicionou uma linha de estorno contra uma comissão já aprovada ou paga. |
none | Nenhuma linha foi criada. reason diz por quê. |
Tipos de comissão
type | Significado |
|---|---|
cpa | Uma por jogador quando o mínimo do deal é atingido pelo primeiro depósito ou pelos depósitos acumulados menos chargebacks, conforme sua base de CPA. |
revshare | Um percentual da receita líquida de jogo (NGR) de um jogador em um período. Negativa em um período em que o jogador ganhou. |
adjustment | A diferença causada por um valor de receita corrigido. |
reversal | O negativo de uma comissão retirada depois de ter sido aprovada ou paga: por um chargeback, ou pelo operador com um motivo. É aprovado na hora e é compensado no próximo pagamento. |
tier | Um complemento de uma faixa por volume do deal: quando um afiliado traz novos jogadores depositantes suficientes em um mês do calendário, a diferença entre o valor da faixa e o valor base é adicionada ao lado de cada comissão desse mês. Fica na mesma retenção que sua comissão, ou é aprovado na hora se ela já estiver aprovada. Negativo quando retira um complemento anterior, depois que sua comissão foi rejeitada ou estornada. |
Status de comissão
Uma linha é gravada uma vez e seus valores nunca mudam. O status muda:
status | Significado |
|---|---|
hold | Aguardando: o fim do período de retenção do deal, ou o que status_reason indica. |
approved | O período de retenção terminou e nada retém a linha. Ela entra no próximo lote de pagamento mensal. Estornos e alguns ajustes já nascem aprovados. |
paid | O item de pagamento que contém a linha foi marcado como pago. |
rejected | Não será paga. status_reason diz por quê, e status_note traz a nota do operador quando houver. |
Valores de status_reason
Vazio quando a linha aguarda apenas o período de retenção e normalmente em comissões aprovadas ou pagas. A falta de taxa de chargeback também pode bloquear uma linha aprovada. Retenções por fraude aguardam o operador ou a expiração configurada do alerta.
status_reason | Com o status | Significado |
|---|---|---|
fx_rate_missing | hold | Falta uma taxa de câmbio necessária. A liquidação aguarda a taxa; fluxos diários SALES usam a data de atividade, postbacks individuais usam seu dia UTC. |
chargeback_fx_missing | hold, approved, paid | Um chargeback ainda não pode ser convertido. O CPA e seus adicionais de faixa não podem entrar em novo pagamento nem ser marcados como pagos em um existente até a taxa chegar e a reconciliação terminar. |
chargeback_reference_missing | hold | Um resumo recebido antes do cadastro contém um chargeback agregado que não identifica o depósito revertido para CPA de primeiro depósito. O cadastro e o resumo são guardados; o CPA resultante fica em retenção até a revisão da referência da transação. |
self_referral | hold | Um alerta de fraude aberto: o jogador parece ser o próprio afiliado. Aguarda o operador liberar ou confirmar o alerta. |
click_velocity | hold | Um alerta de fraude aberto, ou um clique que fez parte de uma rajada: mais cliques em um link, de um mesmo endereço, em um minuto do que a marca permite. Aguarda o operador. |
duplicate_conversion | hold | Um alerta de fraude aberto: um segundo "primeiro" depósito foi informado para o jogador. Aguarda o operador. |
paid_traffic | hold | Um alerta de fraude aberto: o clique que trouxe o jogador trazia o click ID de uma rede de anúncios. Aguarda o operador. |
disposable_email | hold | Um alerta de fraude aberto: o jogador se cadastrou com um domínio de e-mail descartável. Aguarda o operador. |
geo_mismatch | hold | Um alerta de fraude aberto: o jogador se cadastrou num país diferente do país do clique. Aguarda o operador. |
fast_registration | hold | Um alerta de fraude aberto: o jogador se cadastrou dentro do número de segundos definido após o clique. Aguarda o operador. |
affiliate_pending | hold | O afiliado ainda não estava aprovado quando a comissão foi ganha. Quando o afiliado é aprovado, a linha aguarda apenas o seu período de retenção normal. |
affiliate_rejected | hold | A candidatura do afiliado foi rejeitada. |
affiliate_suspended | hold | O afiliado estava suspenso quando a comissão foi ganha. Quando o afiliado é reativado, a linha aguarda apenas o seu período de retenção normal. |
chargeback | rejected, approved | Em uma linha rejeitada: um chargeback a cancelou enquanto estava em retenção. Em uma linha de estorno: ela estorna uma comissão após um chargeback. |
below_threshold | rejected | Quando as taxas ficaram disponíveis, o primeiro depósito qualificado ou os depósitos acumulados líquidos ficaram abaixo do mínimo do deal. |
fraud | rejected, approved | O operador confirmou o alerta de fraude que retinha a linha, ou retirou a comissão por fraude. |
base_rejected | rejected | Um complemento de faixa cuja comissão foi rejeitada enquanto os dois estavam em retenção. |
self_excluded | rejected, approved | O operador retirou a comissão: o jogador se autoexcluiu. Numa linha rejeitada, a comissão ainda não estava em um pagamento; numa linha de estorno, estava. |
duplicate_account | rejected, approved | O operador retirou a comissão: o jogador tem outra conta. |
bonus_abuse | rejected, approved | O operador retirou a comissão por abuso de bônus. |
terms_breach | rejected, approved | O operador retirou a comissão por violação dos termos do programa. |
test_account | rejected, approved | O operador retirou a comissão: o jogador era uma conta de teste. |
other | rejected, approved | O operador retirou a comissão por outro motivo, escrito em status_note. |
Status de pagamento
Um mês fecha em um lote de pagamento com um item por afiliado e moeda. Lotes e itens são tratados no portal; a API mostra o resultado deles como o status paid das linhas de comissão.
| Status do lote | Significado |
|---|---|
draft | O mês foi fechado. O operador revisa os itens. |
approved | Travado. Com as faturas ativadas, cada item pagável recebe um número de fatura. O arquivo bancário (CSV) pode ser baixado e os itens, pagos. |
paid | Todos os itens a pagar foram marcados como pagos. |
| Status do item | Significado |
|---|---|
payable | A pagar neste lote. |
carried | Abaixo do pagamento mínimo, ou não acima de zero: passa para o lote seguinte. |
held | O afiliado tem um alerta de fraude aberto, ou o programa retém pagamentos até a identidade ser verificada e a verificação ainda não foi registrada. O portal diz qual. O operador pode liberar o item, e registrar a verificação de identidade o libera. |
no_details | O afiliado não informou seus dados de pagamento. Fica fora do arquivo bancário. |
written_off | O mês terminou abaixo de zero e o deal do afiliado não leva um mês negativo adiante: o saldo é baixado no fechamento e nada passa para o próximo lote. Com um limite, o item fica carried e registra como baixada a parte acima do limite. |
paid | Marcado como pago. Suas linhas de comissão ficam paid, e o tracker do afiliado é avisado. |
Por que uma linha de arquivo é recusada
Uma linha recusada é contada em rejected, listada em problems como line N: reason e mantida no log de entrada com a própria linha. Além dos motivos pelos quais um evento pode ser recusado:
- A linha não é um CSV válido.
- REG:
registration_dateouplayer_idestá ausente ou ilegível. - SALES:
activitydateouplayer_idestá ausente ou ilegível. - SALES, receita: o jogador não está cadastrado.
- SALES, dinheiro: um valor é negativo, ilegível ou tem casas decimais demais para a moeda.
- SALES: o primeiro depósito supera os depósitos brutos.
- SALES: um dia aceito foi reexportado com totais monetários, moeda ou limites de fuso horário alterados.
- SALES: depósitos ou chargebacks individuais conhecidos superam o resumo do dia.
- SALES: a evidência de primeiro depósito conflita com outro dia ou uma transação conhecida.
- SALES: um chargeback agregado é ambíguo para CPA de primeiro depósito de um jogador já cadastrado.
Resultados no log de entrada
| Status | Significado |
|---|---|
accepted | Gravado, com o que fez. |
duplicate | Já gravado; a primeira resposta foi devolvida. |
rejected | Recusado; o detalhe diz qual campo e por quê. |
bad_signature | O timestamp ou a assinatura estava errado. |
test | Um evento de teste da página Integração. Passa pelo caminho real e não grava nada. |
Estados de uma entrega de postback
| Status | Significado |
|---|---|
queued | Aguardando a primeira tentativa, ou o próximo reenvio. O portal a mostra como aguardando ou repetindo. |
delivered | O tracker respondeu com um status 2xx. |
dead | Todos os reenvios falharam. O portal a mostra como desistida; o afiliado pode reenviá-la manualmente. |
Status de um afiliado
| Status | Significado |
|---|---|
pending | Candidatou-se; o operador ainda não decidiu. |
approved | Ativo no programa. |
rejected | A candidatura foi recusada. |
suspended | Interrompido pelo operador. |
O link de rastreamento
Um link de rastreamento é aberto por um visitante, não chamado pela sua plataforma. Ele grava o clique e responde com um redirecionamento 302 para a landing page da marca. Enquanto a marca não verificou o site, o visitante vê antes uma página curta dizendo para onde o link leva. O host de destino vem das configurações da marca; um link só pode escolher um caminho dentro dele.
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 Parâmetros no link
| Parâmetro | Significado |
|---|---|
sub1 … sub5 | Os valores do próprio afiliado, gravados com o clique e devolvidos nos postbacks. Um valor no endereço substitui o que está fixado no link. |
utm_source utm_medium utm_campaign utm_term utm_content | Gravados com o clique e repassados à landing page. Um valor no endereço substitui o que está fixado no link. |
gclid fbclid ttclid msclkid wbraid | Click IDs das redes de anúncios. Gravados com o clique; disponíveis como macros de postback. Não são repassados. |
Parâmetros acrescentados à URL de destino
| Parâmetro | Significado |
|---|---|
cid | O click ID: 26 caracteres em base32 de Crockford (dígitos e letras maiúsculas sem I, L, O, U). Ele se ordena por tempo. Guarde-o como texto. |
btag | <número do afiliado>_<número do link>: de um a nove dígitos, um sublinhado, de um a nove dígitos. |
utm_source … utm_content | As tags UTM do clique, quando não estão vazias. |
- Se a URL de destino da marca contém
{click_id}na query, o click ID é colocado ali ecidnão é acrescentado. - Um clique no link de um afiliado que não está aprovado é gravado e sinalizado, e chega sem
cidebtag: ele não pode ser atribuído. - Bots, prévias de link, requisições
HEAD, requisições sem user agent e cliques repetidos dentro de uma hora são gravados e sinalizados, não descartados. Os relatórios os deixam de fora. - Outros parâmetros no link não são gravados nem repassados.
- Um link a que o afiliado deu um nome curto também responde em
/go/<name>, exatamente como em/c/<code>. Uma marca com o seu próprio domínio de rastreamento verificado serve os dois caminhos também nesse domínio. - Um código desconhecido é respondido com
404e uma página de erro em HTML, assim como um link cuja marca ainda não definiu um destino.
Postbacks para os trackers dos afiliados
Esta parte não exige trabalho do operador. Cada afiliado adiciona até 10 destinos no portal dele: um template de endereço com macros e os eventos sobre os quais quer ser avisado. Quando um evento é registrado para um dos jogadores do afiliado, a RevRake preenche o template e o chama com uma requisição GET.
Eventos
| Evento | {status} | Quando |
|---|---|---|
registration | lead | Um jogador foi atribuído ao afiliado. |
ftd | sale | Um primeiro depósito rendeu ao afiliado uma comissão CPA. |
commission_approved | approved | Uma comissão foi aprovada ao fim do período de retenção. |
commission_rejected | rejected | Uma comissão em retenção foi rejeitada após uma análise. |
commission_paid | paid | Uma comissão foi paga em um lote de pagamento. |
chargeback | rejected | Um chargeback retirou uma comissão. |
Palavras de status por preset
Um destino criado a partir de um preset envia, em {status}, as palavras que o tracker dele conhece. Os presets do Voluum, do PeerClick e do FunnelFlux Pro, e "Outro / personalizado", enviam as palavras da tabela acima. As palavras seguem o preset que o destino leva; o endereço salvo dele nunca é alterado.
| Evento | 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
Uma macro é um nome entre chaves. É substituída pelo seu valor, codificado para URL. Os nomes são comparados sem diferenciar maiúsculas de minúsculas. Um nome que a RevRake não conhece é enviado como está, então um erro de digitação aparece no log de entregas. Um valor que não é conhecido fica vazio.
| Macro | Significado |
|---|---|
{click_id} | O click ID da RevRake (o cid na URL de destino). Vazio quando o jogador foi atribuído só pelo btag. |
{sub1} … {sub5} | sub1 a sub5 do clique. sub1 normalmente leva o click ID do tracker do afiliado. |
{event} | O nome do evento, como na tabela acima. |
{status} | A palavra que os trackers usam para o evento, como na tabela acima, ou a palavra própria do tracker em um destino criado a partir de um preset (veja a próxima tabela). |
{event_id} | Diferente para cada evento e estável entre reenvios. |
{conversion_id} | Igual para todos os eventos de uma mesma comissão: ftd, commission_approved, commission_rejected, commission_paid e chargeback. Um cadastro tem o seu próprio. Use-o como ID de transação em um tracker que atualiza uma conversão que chega de novo com o mesmo ID, para que a receita seja contada uma vez. |
{player_id} {affiliate_id} {brand_id} {link_id} | O ID do jogador no operador, o número do afiliado, o programa e o número do link. |
{campaign} | O rótulo de campanha do link. |
{commission} {commission_minor} | A comissão, como decimal (40.00) ou em unidades menores (4000). Vazia para um cadastro, 0 para uma comissão rejeitada, negativa para um chargeback. |
{amount} {amount_minor} | O depósito ou a receita por trás da comissão, como decimal ou em unidades menores, na moeda em que foi feito. Vazio para um cadastro. |
{amount_currency} | O código ISO da moeda do depósito. Vazio para um cadastro. |
{commission_currency} | O código ISO da moeda da comissão: a do deal. Vazio para um cadastro. |
{currency} | O código ISO da moeda a que o postback se refere: a moeda da comissão quando há uma comissão, senão a do depósito, senão a moeda de relatório do workspace. |
{occurred_at} {occurred_at_unix} | Quando aconteceu, no formato RFC 3339 ou em segundos Unix. |
{country} {device} {os} {browser} {referer} | O que se sabe sobre o clique: país, tipo de dispositivo, sistema operacional, navegador, referenciador. |
{utm_source} {utm_medium} {utm_campaign} {utm_term} {utm_content} | As tags UTM do clique. |
{gclid} {fbclid} {ttclid} {msclkid} {wbraid} | Click IDs das redes de anúncios, quando o clique os trazia. |
Outros nomes para as mesmas macros
Os trackers usam nomes diferentes para as mesmas coisas. Estes também são aceitos:
{subid} | = {sub1} |
{clickid} | = {click_id} |
{payout} | = {commission} |
{txid} | = {event_id} |
{transaction_id} | = {event_id} |
Presets
O portal do afiliado traz estes templates. O afiliado substitui o host pelo do seu tracker. Cada um segue a documentação do seu tracker: {conversion_id} fica no parâmetro de transação quando o tracker atualiza uma conversão que chega de novo com o mesmo ID, e {event_id} quando ele descartaria os eventos posteriores.
| 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} |
Um exemplo
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 Entrega
- Um postback entra na fila na mesma transação do evento que ele informa, e é enviado em cerca de dez segundos, do mais antigo para o mais novo.
- A requisição é um
GETcom o user agentRevRake-Postback/1. Ela segue no máximo três redirecionamentos e desiste após 5 segundos. Os certificados são verificados. - Uma resposta
2xxé um sucesso. Qualquer outra coisa é uma falha e é reenviada após 1 minuto, 5 minutos, 25 minutos, 2 horas, 10 horas e 24 horas. - Depois do último reenvio, a entrega é marcada como desistida. O afiliado pode reenviá-la manualmente.
- Cada tentativa é registrada com a duração, o status e os primeiros 500 caracteres da resposta.
- Depois de 5 e de 15 falhas seguidas, o dono do destino recebe um e-mail. Com 20, o destino é desligado. As entregas dele, inclusive as de eventos que acontecem enquanto está desligado, continuam entrando na fila e são enviadas quando o afiliado o liga de novo. Um destino que o próprio afiliado desligou não recebe nada novo.
- A RevRake só chama endereços públicos. Endereços de loopback, privados, link-local e de carrier-grade NAT são recusados no momento da conexão, então um redirecionamento não consegue contornar isso.
- O template deve ser um endereço
http://ouhttps://completo, com no máximo 2.000 caracteres.
Por que uma tentativa falhou
timeout | Sem resposta em 5 segundos. |
dns | O nome do host não foi encontrado. |
refused | A conexão foi recusada. |
blocked_address | O endereço é privado ou local. |
tls | Um problema no certificado. |
too_many_redirects | Mais de três redirecionamentos. |
http_error | O tracker respondeu com um status diferente de 2xx. |
other | A conexão falhou por outro motivo. |
Webhooks do operador
Os webhooks informam os sistemas do próprio operador (um CRM, um data warehouse, um canal de chat) sobre o que acontece no programa. Um admin do workspace adiciona um endpoint na página Integração do portal do operador: o endereço no seu servidor, os eventos a enviar e uma descrição opcional. Para cada um desses eventos, a RevRake envia um POST JSON assinado para o endereço. Os outros membros da equipe não podem ver nem alterar os endpoints.
O endereço é um endereço https:// completo em um host público (http:// é aceito, mas use https://). Cada endpoint tem o seu próprio segredo, que começa com whsec_. Ele é mostrado uma única vez, quando o endpoint é criado ou o segredo é rotacionado: copie-o nesse momento. Rotacionar cria um novo segredo na hora, e o antigo deixa de assinar.
Um endpoint também pode ser um canal do Slack ou do Microsoft Teams: escolha “Mensagem no Slack” ou “Mensagem no Microsoft Teams” e cole o endereço de incoming webhook do canal (no Teams, um fluxo “Quando uma solicitação de webhook do Teams for recebida”). Cada evento chega então como uma frase no canal em vez de JSON assinado, e um valor pode manter só os primeiros depósitos a partir desse tamanho.
Eventos
Marque um ou mais por endpoint. Os campos de data estão descritos abaixo; um campo que não se aplica é omitido.
| Evento | Campos de data | Quando |
|---|---|---|
affiliate.applied | affiliate_number affiliate_name email promotes_on traffic | Alguém se candidatou na página do seu programa ou por um link de convite de um deal. É enviado quando a candidatura é feita, o que pode ser antes de o candidato confirmar o e-mail. Um afiliado que você mesmo adiciona e convida envia affiliate.approved no lugar. |
affiliate.approved | affiliate_number affiliate_name email reason decided_by invited | Você aprovou um afiliado: uma candidatura nova, ou uma que você tinha rejeitado ou suspendido. Um afiliado que você mesmo adiciona e convida é aprovado na hora e envia este evento com invited igual a true. |
affiliate.rejected | affiliate_number affiliate_name email reason decided_by | Você rejeitou uma candidatura. |
affiliate.suspended | affiliate_number affiliate_name email reason decided_by | Você suspendeu um afiliado aprovado. |
player.registered | player_id occurred_at attributed affiliate_number affiliate_name attribution_reason | Um jogador foi cadastrado, por um evento assinado ou por uma linha de um arquivo REG, atribuído ou não. Uma vez por jogador. |
commission.created | player_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currency | Uma linha de comissão foi criada: CPA qualificado pela base de primeiro depósito ou depósitos acumulados do deal, ou revenue share ou ajuste da receita líquida informada. Adicionais de faixa e estornos não enviam esse evento. |
commission.approved | player_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currency | Uma comissão em retenção foi aprovada porque o período de retenção terminou, complementos de faixa incluídos. Uma linha aprovada desde o início não envia nenhum. |
commission.rejected | player_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currency | Uma comissão em retenção foi rejeitada porque você confirmou o alerta de fraude que a retinha. commission é zero. Um CPA cancelado por um chargeback envia commission.reversed no lugar. |
commission.paid | player_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currency | Uma linha de comissão foi paga: um evento por linha de um item de pagamento marcado como pago, linhas de estorno e de faixa incluídas. |
commission.reversed | player_id occurred_at attributed affiliate_number affiliate_name commission_id commission_type amount amount_currency commission commission_currency | Um chargeback tomou de volta um CPA: cancelado enquanto em retenção, ou estornado por uma nova linha depois de aprovado ou pago. commission_id identifica o CPA, commission é o seu negativo e amount é o depósito que sofreu o chargeback. |
payout.batch_closed | batch_id period reference items payable_by_currency closed_by_hand | Um mês foi fechado em um lote de pagamento em rascunho, por uma pessoa ou pelo fechamento agendado. |
payout.batch_approved | batch_id | Um lote de pagamento em rascunho foi aprovado e travado. |
payout.paid | batch_id item_id affiliate_number affiliate_name currency amount | Um item de um lote aprovado foi marcado como pago. Um lote com todos os itens pagos não envia evento próprio. |
tracking.health_alert | brand kind since quiet_hours clicks_at_least | Os links de uma marca receberam pelo menos o número de cliques definido nas horas definidas e nenhum cadastro chegou (página Integração, Saúde do rastreamento). Enviado uma vez; verificado a cada hora. |
tracking.health_cleared | brand raised_at cleared_at | Chegou o primeiro cadastro após um alerta de saúde do rastreamento, e o alerta é encerrado. |
flag.raised | kind detail affiliate_number affiliate_name | Um novo sinal de fraude foi criado sobre um afiliado (por uma regra, um primeiro depósito repetido ou autoindicação). Sinais de rajadas de cliques ficam só na página Sinais. |
postback.destination_off | destination failures affiliate_number affiliate_name | O destino de postbacks de um afiliado foi desativado após as falhas seguidas de entrega que a escala de novas tentativas permite. |
file.late | source date | Um arquivo diário buscado em horário programado não tinha chegado três horas depois do horário. Uma vez por arquivo e dia. |
webhook.test | message | Somente pelo botão "Enviar teste". Não pode ser marcado, não é reenviado e não aparece no log de entregas. |
O corpo
Toda requisição leva um objeto JSON:
| Campo | Tipo | Significado |
|---|---|---|
id | string | O ID do evento, um UUID. O mesmo para todo endpoint que recebe o evento e em todo reenvio: use-o para descartar repetições. |
type | string | O evento, como na tabela acima. |
created_at | string | Quando o evento entrou na fila, no formato RFC 3339 em UTC, com frações de segundo. |
data | object | Os fatos do evento. Veja os campos abaixo. |
{
"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"
}
} As chaves podem vir em qualquer ordem, e o espaçamento do JSON não é fixo. Verifique os bytes como foram recebidos, depois interprete-os.
Cabeçalhos
| Cabeçalho | Valor |
|---|---|
RevRake-Event | O evento, igual a type no corpo. |
RevRake-Delivery | O ID desta entrega a este endpoint, um UUID. O mesmo em todo reenvio, e quando uma entrega é enviada de novo à mão. |
RevRake-Timestamp | Quando esta tentativa foi enviada, em segundos Unix. Novo a cada tentativa. |
RevRake-Signature | O HMAC-SHA256 em hex minúsculo, com o segredo do endpoint, de <timestamp>.<raw body>. Nova a cada tentativa. |
A requisição também leva Content-Type: application/json e o user agent RevRake-Webhook/1.
POST /revrake-webhook HTTP/1.1
Host: example.com
Content-Type: application/json
User-Agent: RevRake-Webhook/1
RevRake-Event: commission.created
RevRake-Delivery: 0199b2c9-0b7e-7d02-8a41-3c5e6f708192
RevRake-Timestamp: 1791191571
RevRake-Signature: <hex HMAC-SHA256 of "1791191571.<raw body>"> Os campos de data
| Campo | Tipo | Significado |
|---|---|---|
affiliate_number | integer | O número do afiliado. |
affiliate_name | string | O nome do afiliado. |
email | string | O endereço de e-mail com que o afiliado entra. |
promotes_on | string | O que o candidato escreveu sobre onde promove. |
traffic | array of string | As fontes de tráfego que o candidato marcou: seo, telegram, paid_social, youtube, email ou offline. |
reason | string | O motivo informado ao afiliado. Sempre presente em uma rejeição ou suspensão; pode estar vazio em uma aprovação. |
decided_by | string | O endereço de e-mail do membro da equipe que decidiu, ou que adicionou o afiliado. |
invited | boolean | true quando você mesmo adicionou e convidou o afiliado, sem candidatura. Omitido nos outros casos. |
player_id | string | O seu ID do jogador. |
occurred_at | string | Quando aconteceu, no formato RFC 3339: o cadastro, o depósito, o fim do período de receita ou o chargeback. Em uma aprovação, rejeição ou pagamento: o momento da mudança. |
attributed | boolean | Se o jogador pertence a um afiliado. Sempre true para uma comissão. |
attribution_reason | string | Por que o jogador foi ou não atribuído: um dos motivos de atribuição. |
commission_id | string | O ID da linha de comissão na RevRake: o id da linha em GET /v1/commissions. O mesmo em todo evento sobre essa comissão. |
commission_type | string | O tipo da linha de comissão: cpa, revshare, adjustment ou tier, e reversal para uma linha de estorno em commission.paid. Em commission.reversed, o tipo do CPA que foi estornado. |
amount | string | Para uma comissão: o depósito ou a receita líquida por trás dela, como decimal, na sua própria moeda. Para payout.paid: o valor do item, como decimal. |
amount_currency | string | O código ISO da moeda de amount. |
commission | string | A comissão, como decimal na moeda do deal (40.00). Negativa em um estorno, um ajuste para baixo e um período em que o jogador ganhou. |
commission_currency | string | O código ISO da moeda da comissão: a do deal. |
batch_id | string | O ID do lote de pagamento na RevRake, um UUID. |
period | string | O mês que o lote fecha, YYYY-MM. |
reference | string | A referência do lote, a mesma do arquivo bancário, como po_2026-09_demo. |
items | integer | Quantos itens o lote tem, qualquer que seja o status deles. |
payable_by_currency | object | Por moeda, a soma dos valores de todos os itens, como decimal (1250.00), qualquer que seja o status, itens que passam para o mês seguinte incluídos. |
closed_by_hand | boolean | true quando uma pessoa fechou o mês, false no fechamento agendado. |
item_id | string | O ID do item de pagamento na RevRake, um UUID. |
currency | string | A moeda do item. |
message | string | Uma frase dizendo que o teste chegou. |
Verifique uma requisição
- Leia o corpo bruto como bytes, antes de qualquer interpretação do JSON.
- Verifique se
RevRake-Timestampestá a no máximo 5 minutos do seu relógio, e recuse a requisição caso contrário, para que uma requisição gravada não possa ser reproduzida mais tarde. - Calcule o HMAC-SHA256 em hex do timestamp, um ponto e o corpo bruto com o segredo do endpoint, e compare-o com
RevRake-Signatureem tempo constante. - Só então interprete o corpo. Se você já tratou o seu
id, responda2xxe não faça nada. - Responda com qualquer
2xxem até 5 segundos, e faça o trabalho demorado depois.
A mesma verificação em Node.js e Python, como a página Integração a mostra:
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", "")) Entrega, reenvios e desligamento
- Uma entrega entra na fila na mesma transação da mudança que ela informa, então um evento é enviado se e somente se a mudança foi gravada. Ela é enviada em cerca de dez segundos, as mais antigas primeiro.
- A entrega é pelo menos uma vez: o mesmo evento pode chegar mais de uma vez, por exemplo quando a sua resposta se perde no caminho. Descarte repetições pelo
iddo corpo. - A ordem não é garantida: um reenvio pode chegar depois de um evento posterior. Ordene os eventos por
created_atouoccurred_at, não pelo momento em que chegam. - Uma resposta
2xxem até 5 segundos é um sucesso. Qualquer outra coisa é uma falha e é reenviada após 1 minuto, 5 minutos, 25 minutos, 2 horas, 10 horas e 24 horas, com o mesmo corpo e um timestamp e uma assinatura novos. - Depois do último reenvio a entrega é marcada como "desistiu". Um admin pode enviá-la de novo pelo log de entregas, com o botão "Enviar novamente"; ela então recebe todo o calendário de reenvios outra vez.
- Depois de 20 tentativas falhas seguidas o endpoint é desligado. Os seus eventos continuam na fila, e tudo o que entrou na fila é enviado quando um admin o liga de novo. Nenhum e-mail é enviado quando isso acontece: o estado de cada endpoint está na página Integração.
- Um endpoint que você mesmo desliga não recebe nada novo: nenhum evento entra na fila para ele enquanto está desligado.
- A RevRake só chama endereços públicos: desiste após 5 segundos e verifica os certificados. Endereços de loopback, privados, link-local e de NAT de operadora são recusados. Um redirecionamento não é seguido: uma resposta
3xxé uma falha com o erroredirect, e o log de entregas mostra o endereço para onde ela apontava.
Teste e leia o log de entregas
- Clique em "Enviar teste" em um endpoint: um evento
webhook.testé enviado na hora, assinado como um real, e você vê o status que o seu endpoint respondeu e quanto tempo levou. Um teste não é reenviado, não aparece no log de entregas e não conta como falha. - O log de entregas de um endpoint mostra as suas 100 entregas mais recentes: o evento, o estado ("aguardando", "repetindo", "desistiu" ou "entregue"), o número de tentativas, o último status ou erro, os primeiros 500 caracteres da sua resposta, a próxima tentativa e o corpo como foi enviado.
- Uma tentativa falha é descrita com as mesmas palavras de um postback (veja por que uma tentativa falhou), mais
redirect: o seu endpoint respondeu com um3xx. Os estados são os de uma entrega 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."
}
} Boas práticas
- Guarde o segredo no seu servidor, nunca em uma página ou em um app. Se ele vazar, rotacione-o e passe o seu endpoint para o novo na hora: o segredo antigo para imediatamente.
- Responda a uma requisição cuja assinatura não confere com um
4xx. Ela é reenviada, assinada com o segredo atual, então uma entrega feita enquanto você rotaciona não se perde. - Guarde o
idde cada evento que você tratou, e ignore um evento que você já viu. - Responda primeiro, trabalhe depois: coloque o evento em uma fila sua e responda
2xx, para que um banco de dados lento nunca faça a RevRake reenviar. - Informe o endereço final do seu endpoint. Um redirecionamento não é seguido: a tentativa falha com
redirect, e o log de entregas mostra o endereço a usar no lugar. - Use
commission_idpara juntar os eventos sobre uma comissão, e concilie comGET /v1/commissions: uma leitura noturna dos últimos 60 dias pega qualquer coisa que tenha faltado. - Marque só os eventos que você usa. Cada um é uma requisição ao seu servidor.
Arquivo OpenAPI
Os quatro endpoints assinados, com todos os status e motivos como enumerações, estão descritos em openapi.yaml (OpenAPI 3.1), para geradores de código e clientes de API. O endereço dele não muda.
Pronto para conectar? Crie o seu programa e obtenha sua chave.
Você mesmo cria o seu programa: cadastre-se, confirme seu e-mail e em poucos minutos você está dentro. Gratuito para operadores, para sempre. Sem cartão.
Dúvidas? Escreva para hello@revrake.com