Connect your platform to RevRake.
A step-by-step guide for an operator's developer and for an affiliate. Your platform does two things: it keeps a tag from the landing URL, and it reports players, as signed requests or as daily files. Every field, limit and error code is in the API reference.
How it fits together
An affiliate shares a tracking link. RevRake stores the click and sends the visitor to your landing page with two tags. Your platform keeps a tag until the player registers, then reports the player and their money to RevRake. RevRake works out the commission, tells the affiliate's tracker and closes the month into a payout.
- Affiliate Tracking link
- Visitor track.revrake.com Click stored
- Your landing page arrives with
cidandbtag - Your platform keeps the tag, registers the player
- RevRake app.revrake.com attribution, commissions, ledger
- Affiliate's trackerpostbackMonthly payoutCSV
Your platform → RevRake: Signed events or daily files
For the operator's developer
The steps, in the order you will do them.
1Create your program
Sign up at app.revrake.com/signup with your email and confirm it with the link we send. The link works once, for 48 hours. Confirming creates your program and signs you in as its admin. It is free and needs no card.
Then verify the site your links land on. Open the Brand page, choose "Verify your site" and publish what it shows: a DNS TXT record revrake-verify=<token> on the host or a parent domain, or the tag <meta name="revrake-verify" content="<token>"> on the landing page. Then press the check.
- Until the site is verified, a visitor who opens one of your tracking links first sees a short page saying where the link leads.
2Get your key
Open the Integration page of your operator portal. It shows the endpoint, your key ID (it starts with pb_) and the secret. Only a workspace admin can see the secret or rotate the key.
Every request carries three headers: the key ID, the current Unix time in seconds, and the hex HMAC-SHA256 of <timestamp>.<body> under the secret. The reference has the recipe with samples in curl, Node.js, Python, PHP and Go, and a test vector to check your code against.
- Rotating the key makes a new one and stops the old one at once. Switch your platform to the new key right away.
- Keep the secret on your server. Never put it in a page or an app.
3Keep cid or btag at registration
A tracking link redirects the visitor to your landing page and adds two parameters:
https://track.revrake.com/c/<code>?utm_source=telegram&sub1=<tracker click id>
→ https://your-site.example/landing?cid=<click id>&btag=1001_1&utm_source=telegram Store one of them with the visitor (a cookie or your session) and save it on the player when they register. That value is what attributes the player.
cidis the click ID: 26 letters and digits. Treat it as an opaque string and store it as text. It gives the most exact attribution.btagis<affiliate number>_<link number>, digits only, the form casino platforms already store on a player. Use it when your platform has a btag field and no place for a click ID.- If the landing URL in your brand settings contains
{click_id}, the click ID is put there instead of being added ascid. - UTM tags on the tracking link are passed on to your landing page.
4Report registrations
When a player registers, send a registration event with your player ID and the click_id, the btag, or both. RevRake attributes the player once, at that moment, and the answer says to which affiliate and why.
{"type":"registration","player_id":"PLR-1001","click_id":"01K6QF3M8Z5T7W9XB2C4D6E8GH","btag":"1001_1"} {
"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"
}
} A player is attributed by your brand's policy, set on the Integration page: last click (the default) or first click, inside an attribution window of 1 to 365 days (30 by default). The click ID is tried first, then the btag, unless the policy says the btag wins when the two disagree. Send every registration, also those without a tag: they are recorded as not attributed, and their later deposits are then known not to be first deposits of an affiliate's player. When the policy says the promo code wins, a code that matches a link is tried before both, and one that does not falls back to them. A deal may set its own window, which replaces the policy's for clicks on its affiliates' links.
- Send
email_hashandipif you want the self-referral check to work on more than the click. - Send
country, the player's two-letter country code (ISO 3166-1 alpha-2, such asGB), if any of your deals does not pay for some countries. Without it, the country of the click that brought the player is used. - Send
tswhen you report late, so the attribution window is measured from the real registration time. - Send
promo_codewhen the player typed a promo code at sign-up. It attributes the player only when neither the click ID nor the btag does (see the next step). - Send
email_domain, the part of the player's email after the@, if you switch on the throwaway-email rule. Send the domain only: if a whole address arrives, only the domain is kept on the player, but the inbound log still shows the request as it arrived.
5Use promo codes
A promo code credits a player to an affiliate without a click: the player types it when they sign up. On the Promo codes page, an admin adds a code for an approved affiliate, and the code becomes one of that affiliate's links, shown on their Links page. Create the same code in your platform, then send it with the registration as promo_code, or in the promo_code column of the REG file.
{"type":"registration","player_id":"PLR-1003","promo_code":"GARAGE50"} {
"status": "accepted",
"event_type": "registration",
"event_id": "0199b2c5-1d40-7e82-b3a1-6c0f2d9e4b17",
"attribution": {
"attributed": true,
"reason": "promo_code",
"affiliate_number": 1001,
"link_number": 7,
"policy_version": 1,
"window_days": 30,
"model": "last_click"
}
} - The click ID and the btag come first. The promo code attributes the player only when neither of them does, and the reason is then
promo_code. - Codes are not case-sensitive:
GARAGE50andgarage50are the same code. A code is 2 to 40 letters, digits, hyphens or underscores. - Retiring a code stops it from crediting new players; the players it brought stay with the affiliate. A retired code can never be used again in the program.
- When nothing else was sent to attribute the player, a code RevRake does not know is answered with the reason
unknown_promo_code, and a retired one withpromo_code_retired. A code of an affiliate who is not approved givesaffiliate_inactive.
6Report deposits
Send a deposit event for each deposit, with your transaction ID in txn_id. The deal chooses whether CPA requires the first deposit or cumulative deposits, net of chargebacks, to reach its minimum. Qualification creates one CPA commission per player, on hold.
{"type":"deposit","player_id":"PLR-1001","txn_id":"TX-88213","amount":"25.00","currency":"KES","first":true} {
"status": "accepted",
"event_type": "deposit",
"event_id": "0199b2c9-03aa-7e10-b6d2-91c07f5e2a18",
"commission": {
"effect": "created",
"type": "cpa",
"amount_minor": 4000,
"status": "hold"
}
} - Send
first: trueon the player's first deposit if your platform knows it. Without it, a deposit counts as first when RevRake knows no earlier one for the player. - Send the deposit's own
currency. A deposit in another currency than the deal's is compared with the deal at that day's exchange rate. - A deposit may arrive before its registration. It is kept, and priced when the registration comes.
7Report chargebacks
Send a chargeback event with its own txn_id and the original deposit’s txn_id in ref_txn_id. It reverses that whole deposit. For cumulative CPA, the commission is taken back only if the remaining qualifying total falls below the minimum: a held commission is cancelled; an approved or paid one gets a reversal row.
{"type":"chargeback","txn_id":"CB-5001","ref_txn_id":"TX-88213"} - The deposit must have been reported first. A chargeback of an unknown deposit is refused, not kept.
- A deposit can be charged back once.
8Report net gaming revenue
For revenue share deals, send an ngr event per player and period: the player's net gaming revenue for a day (YYYY-MM-DD) or a month (YYYY-MM), negative when the player won. It earns the share set in the deal, on hold.
{"type":"ngr","player_id":"PLR-1001","period":"2026-10-03","amount":"118.40","currency":"KES"} - The player must be registered first; revenue for an unknown player is refused.
- If a figure changes, send the new figure for the same period. The difference is recorded as an adjustment; nothing is rewritten.
- Choose days or months and stay with it. A month and its first day are different periods:
2026-10is not2026-10-01. A month is priced by the deal version in effect on its last day and held from then. - Optionally add
ggr,bonuses,feesandtaxes: how the net revenue was reached. The affiliate sees them beside the commission; the commission is always priced onamount.
9Choose live events, batches or the daily file
All three feed the same commission ledger. Live events and batches report individual transactions; SALES files report daily summaries. Choose what your platform can provide.
POST https://app.revrake.com/v1/files?filename=sales-2026-10-03.csv - Live events. One signed request per event, as it happens. The affiliate sees the player within seconds. Use this if your platform can call a URL on registration and on deposit.
- Batches. The same events as a JSON array of up to 1,000 per request, for example from a job that runs every few minutes or for a backfill. Each event is answered on its own.
- Daily files. The REG and SALES CSV files your platform already exports for an affiliate system, uploaded on the Integration page, pushed to
POST /v1/files, or fetched by RevRake from an address your platform publishes them at (next step). One row per player per day. Send the REG file before the SALES file of the same day: revenue for a player who is not registered yet is refused. - A SALES summary covers its player’s deposits and chargebacks for the activity day and currency, in the file timezone. Covered postbacks are not added again, whichever arrives first; their transaction IDs remain usable for chargebacks. Conflicting totals are refused. Distinct postback transaction IDs still represent distinct deposits, even with equal amounts.
- SALES requires
deposits(the day’s gross deposits, including FTD),first_deposit_amount(only on the actual first-deposit day, already included in gross) andchargeback(the separate amount charged back that day). These are daily amounts, not lifetime totals. Empty cells mean zero; amounts must be nonnegative. One immutable summary is kept per brand, player and day: unchanged re-exports replay, changed money or currency conflicts. - Money received before REG is kept and priced when registration arrives; rejected NGR must be resent after REG. Daily money uses the activity date’s exchange rates. Missing FX or an ambiguous first-deposit chargeback can hold payment. Check rejected events and the inbound log; see the complete SALES contract before connecting your export.
10Let RevRake fetch the daily file
If your platform publishes each day's file at a web address, RevRake can fetch it by itself. On the Integration page, an admin adds a file address: a name (such as REG or SALES), the address, how to sign in, and the time of day. Every day at that time, in your workspace timezone, RevRake fetches yesterday's file within a few minutes and imports it exactly like an upload.
https://reports.your-platform.example/affiliates/reg-{date}.csv
→ GET https://reports.your-platform.example/affiliates/reg-2026-10-04.csv - In the address,
{date}becomes the day of the file asYYYY-MM-DD, and{yyyymmdd}becomesYYYYMMDD. Use one address per file: one for REG, one for SALES. - Sign-in: none, a user name and password (HTTP Basic), or a token sent as
Authorization: Bearer. A password or token is only sent to anhttps://address. - A fetch that does not import a file, for any reason (a
404or any other answer than a2xx, a network error, a file that is too large or cannot be read), is tried again every hour until the next day's fetch. Each address is fetched on its own, so one that fails does not hold up the others. When it is 3 hours late, the workspace admins get one email, and the Integration page shows the file as late. - The next day's fetch moves on to the next day. To fill in a missed day, or to test the address, press "Fetch now" and choose the day. A file fetched twice records nothing twice.
- Give the REG file an earlier time than the SALES file: revenue for a player who is not registered yet is refused.
- A file may be up to 32 MB. RevRake fetches only from public addresses, verifies certificates and gives up after one minute. The last 30 fetches of each address are listed with their outcome.
11Test before you go live
The Integration page can send a test event: it runs a registration through the real path and shows what would happen, and stores nothing. Use it with a cid from a real click on one of your tracking links.
Every request signed with your key and every file row that was imported or refused is in the inbound log on the same page with its outcome, the reason and the body as it arrived. It shows the latest 50 of the last 7 days. The IP address in a body is never stored, and a long body is cut at 4,000 characters.
- Check your signing code against the test vector before you send anything.
- Sending the same event twice is safe. The second answer is the first one with
"status":"duplicate".
12Choose your fraud rules
On the Flags page, Rules tab, an admin switches the fraud rules on and off. Each rule raises its own flag on a player it catches. The player stays attributed, and their commissions wait on hold until someone releases or confirms the flag in the review queue. Self-referral and click bursts are on from the start; the rules below are off until you switch them on.
- Paid ad clicks. The click that brought the player carried an ad network's click ID (
gclid,wbraid,fbclid,msclkidorttclid), which can mean the affiliate bids on your brand name. - Throwaway email. The domain of the player's email is on a public list of disposable email domains. It needs
email_domainon the registration. - Country mismatch. The
countryof the registration differs from the country of the click. - Registration soon after the click. The player registered within the number of seconds you set (up to 3,600) after the click; a sign-up that fast looks scripted.
- Shared payout account. An affiliate saves payout details that another affiliate of the program already uses. This flag holds no commission, but while it is open the affiliate's payout line is held at the monthly close. The account number and routing number must both match, ignoring case, spaces and punctuation; an account number with fewer than four letters or digits is not compared. A crypto wallet address or an e-wallet account counts as the account number. Only the affiliate who saves the details is flagged.
- The player rules run once, at registration, on attributed players; the paid-click, country and timing rules need the click that brought the player. A rule applies from the moment it is saved, not to earlier players.
- Open flags can decide themselves after a number of days you choose (1 to 365; 0, the default, means never), released or rejected. In the review queue you can release or confirm up to 200 flags at once.
13Go-live checklist
- The landing page keeps
cidorbtaguntil the player registers, also when they come back later in the same browser. - Your signing code reproduces the test vector, and your server clock is synchronised (NTP).
- A real click, then a test registration with its
cid, shows the right affiliate. - Registrations are sent for every player, not only for tagged ones.
- Deposits carry a stable
txn_idand their currency. - On a timeout or a
5xxyour platform sends the event again, with a fresh timestamp. - A
422is logged on your side and looked at: it will not succeed on a retry. - The inbound log shows
acceptedfor each event type you send.
14Pull reports and commissions into your back office
Your backend can read what the portal shows, with the same key and the same three headers: GET /v1/reports answers the report of the Reports page, as JSON or as CSV, and GET /v1/commissions answers the commission ledger page by page. A read has no body, so the signature covers the path and the query exactly as you send them. The reference has every parameter and field.
GET https://app.revrake.com/v1/reports?by=link&days=7 GET https://app.revrake.com/v1/commissions?from=2026-09-01&to=2026-10-01&per_page=500 - A commission's status changes after the row is written: on hold, then approved, then paid, or rejected. Do not only fetch new rows. Read a period again, for example the last 60 days every night, and update the rows you already have by their
id. - Amounts are in minor units, with the currency next to them. Never add up amounts of different currencies; use
reporting_minorfor totals in your reporting currency. - At most 120 reads a minute per key. Every answer says how many are left in
X-RateLimit-Remaining. On a429, wait the seconds given inRetry-Afterand send the request again. - Never give your key to an affiliate: it reads the whole program and can send events. Each affiliate issues their own key, which reads only their own numbers.
- The same reports and the ledger can also be downloaded as CSV in the portal.
15Hear about changes in your own systems
Webhooks send what happens in your program to your own systems (a CRM, a data warehouse, a chat channel) as it happens: applications and decisions on affiliates, registered players, commissions as they are created, approved, rejected, paid or reversed, and payouts. On the Integration page, an admin presses "Add an endpoint", enters the address on your server and ticks the events. The signing secret is shown once: copy it then.
{
"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"
}
} Each event is a JSON POST signed with that secret, with a body like the one above. The reference lists every event and field, the headers, and the verification code in Node.js and Python.
- Verify the signature over the raw body before you parse it, and answer with a
2xxwithin 5 seconds. - Drop repeats by the body's
id: an event can arrive more than once. - Press "Send test" to check your endpoint. The delivery log of each endpoint shows what was sent and what your server answered.
- A failed delivery is retried for about a day and a half. After 20 failed attempts in a row the endpoint is switched off; events keep queuing and are sent when you switch it back on.
16Troubleshooting
bad_signature. Sign the exact bytes you send: the same string, not a re-serialised copy of the JSON. The signed text is the timestamp, a dot, then the body. The signature is lower-case hex. Check the secret has no trailing space or line break.bad_timestamp. The timestamp must be Unix seconds (not milliseconds) and within five minutes of the real time. Synchronise the server clock, and sign each retry with a fresh timestamp.unknown_key. The key ID is mistyped, or the key was rotated. The current one is on the Integration page.- Everything is a duplicate. Registrations use
player_id; deposits and chargebacks usetxn_id. Reuse an ID only for an identical retry. Changed deposit money or a changed chargeback reference conflicts. Use a distinct ID for each real transaction. - Players are not attributed. Look at the
reasonin the answer or the inbound log.no_tag: the landing page lost the tag before registration.unknown_clickorunknown_btag: the value was changed or cut on the way.outside_window: the click is older than the attribution window.affiliate_inactive: the affiliate is not approved.unknown_promo_codeorpromo_code_retired: the promo code is not one of yours, or was retired. - I report both ways while moving integrations. A SALES summary covers postbacks for its player, activity day and currency in the file timezone. Amounts count once regardless of arrival order, and actual
txn_idvalues stay usable. A summary below known transactions, or inconsistent first-deposit evidence, is refused. Different postback transaction IDs still count as separate deposits. - A deposit arrived before its registration. The answer has
"waiting_for_player": true. Nothing is lost: send the registration, and the deposit is priced then. - A deposit earned nothing. The
commission.reasonsays why:unattributed,not_first,below_threshold,country_blocked,no_cpa_in_deal,already_earnedorno_deal_version. - A commission is on hold with "exchange rate missing". The deposit is in a currency for which there is no rate for that day yet. Rates are refreshed hourly; you can also enter a rate for the day on the Rates page. The commission is settled as soon as a rate exists.
bad_signatureon a read. For aGET, sign the timestamp, a dot, then the path and the query exactly as sent, in the same order and with the same encoding:/v1/reports?by=link&days=7. With no query, sign the path alone.- A field is refused. A field that is not in the reference is refused, so a typo is never silently ignored. The answer names the
fieldand says what to fix.
For affiliates
Links and postbacks are set up in your affiliate portal and need no key. A key is only needed if you want to read your numbers by API.
Links, sub-IDs and UTM tags
Create one tracking link per campaign on the Links page. Each link has its own short address and its own btag, and can land on a page of the program's site that you choose.
https://track.revrake.com/c/a8Kq2Zx?sub1={clickid}&utm_source=telegram&utm_campaign=october Add your own values to the link when you place it. They are stored with each click:
sub1tosub5: up to 200 characters each. Put your tracker's click ID insub1; it comes back in your postbacks.utm_source,utm_medium,utm_campaign,utm_term,utm_content: stored with the click and passed on to the landing page.- A value fixed on the link in the portal is used unless the address you place carries its own.
- Bots, link previews and repeat clicks are stored and flagged, and left out of your click counts.
- Give a link a short name to say on a stream or print: it also opens at
track.revrake.com/go/<name>. Each link has a QR code to download as PNG or SVG.
Send conversions to your tracker
On the Postbacks page, add a destination: choose your tracker, replace the host in the address with your tracker's, and tick the events you want to hear about. Anything in braces is a macro, filled in for each conversion.
The portal ships these presets. In each, your tracker's click ID travels in sub1, and {status} carries the words that tracker knows:
| Tracker | Put in sub1 of your link | Address template |
|---|---|---|
| Keitaro | {subid} | https://YOUR-TRACKER-DOMAIN/POSTBACK-KEY/postback?subid={sub1}&status={status}&payout={commission}¤cy={currency}&tid={conversion_id} |
| Binom | {clickid} | https://YOUR-TRACKER-DOMAIN/click?cnv_id={sub1}&payout={commission}&cnv_status={status}&cnv_currency={currency} |
| Voluum | {clickid} | https://YOUR-TRACKER-DOMAIN/postback?cid={sub1}&payout={commission}¤cy={currency}&txid={event_id}&et={event} |
| RedTrack | {clickid} | https://YOUR-TRACKER-DOMAIN/postback?clickid={sub1}&sum={commission}&status={status}&type={event}&rdtk_event_id={event_id} |
| BeMob | {clickId} | https://YOUR-TRACKER-DOMAIN/postback?cid={sub1}&payout={commission}&txid={conversion_id}&status={status} |
| PeerClick | {clickid} | https://YOUR-TRACKER-DOMAIN/postback?cid={sub1}&payout={commission}&txid={conversion_id}&status={status}¤cy={currency} |
| FunnelFlux Pro | {hit} | https://YOUR-TRACKER-DOMAIN/pb/?hit={sub1}&tx={conversion_id}&rev={commission}&status={status} |
For any other tracker, choose "Other / custom" and write the address with the macros you need.
Step-by-step guides per tracker: Keitaro, Binom, Voluum, RedTrack, BeMob, PeerClick, FunnelFlux Pro.
- An account can have up to 10 destinations.
- A registration carries no money:
{commission}and{amount}are empty for it. - A macro RevRake does not know is sent as written, so a typo shows in the delivery log.
Test it and read the delivery log
Press "Send test" on a destination: a made-up conversion is sent at once and you see what your tracker answered. Every real postback is a row in the delivery log, with each attempt and the tracker's answer.
- A failed delivery is retried after 1 minute, 5 minutes, 25 minutes, 2 hours, 10 hours and 24 hours. After the last try it is marked as given up, and you can send it again by hand.
- After 5 and after 15 failures in a row you get an email. At 20 the destination is switched off; fix the address and switch it back on, and every postback that queued meanwhile is sent. A destination you switch off yourself gets nothing new.
- Your tracker must be reachable on a public address and answer with a
2xxstatus within 5 seconds.
Read your own numbers by API
If you keep your own reporting, create a key on the API tab of your affiliate portal. It starts with ak_. The secret is shown once, when the key is created: copy it then. With it you can call GET /v1/reports, /v1/commissions, /v1/affiliates, /v1/links and /v1/deals, signed as the reference describes, and you get your own clicks, registrations, first deposits and commissions, and nothing of anyone else.
GET https://app.revrake.com/v1/reports?by=link&days=7 - Your key cannot send events and cannot read other affiliates.
- Creating a new key stops the old one at once. You can also revoke the key and have none.
- The key works while your account is approved in the program. If it is not, the answer is
403affiliate_inactive. - A commission's status changes after the row is written (on hold, approved, paid, or rejected). Read a period again instead of only fetching new rows.
- Never ask the operator for their key, and never share yours. Without a key, the same numbers are in your portal, with CSV downloads.
Ready to connect? Create your program and get your key.
You create your program yourself: sign up, confirm your email, and you are in within a few minutes. Free for operators, forever. No card.
Questions? Write to hello@revrake.com