Skip to content

RevoSurge Partner Postback API

Audience: Engineers, technical integrators, affiliate/partner managers

The Partner Postback API lets an operator or affiliate platform report conversions back to RevoSurge from its own back office. Postbacks are plain HTTP GET callbacks with macros in the query string — the format affiliate back offices already speak — so the integration is a one-time URL registration rather than a code change on your side.

Postback vs. Server Events API

Partner PostbackServer Events API (v3)
Who fires the callYour affiliate back officeYour backend
TransportGET + query-string macrosPOST + JSON envelope
AuthenticationStatic key in the k parameterX-API-KEY header
SetupRegister a URL per event typeWrite an integration
Best forOperators whose back office already emits postbacksFull control over the event catalog and payload

TIP

The two are not mutually exclusive. Postbacks are typically used for the settlement events an operator's back office owns (registration, deposits, revenue share), while the Server Events API carries the richer in-product event stream.

Base URL

EnvironmentBase URL
Productionhttps://mmp.revosurge.com

NOTE

RevoSurge issues your partner slug and your key during onboarding. {partner} in the paths below stands for your slug — substitute it before registering the URLs.

Authentication

Every postback must carry the static key RevoSurge issued you, in the k query parameter.

ParameterRequiredValue
kYesYour postback key
  • The key is compared in constant time; a mismatch returns 403 and the postback is not stored.
  • RevoSurge may additionally restrict your postbacks to an egress IP allowlist. Tell us your outbound addresses during onboarding so a later network change on your side does not turn into silent 403s.
  • k is stripped from the stored event and redacted from request logs. It never reaches the event record.

WARNING

The key travels in the URL, in plain text, and it will be stored in your back office. Treat it as a shared secret of medium sensitivity: do not reuse it elsewhere, and ask RevoSurge for a rotation if it leaks. Rotation is coordinated — we allow the new key before you switch, because a unilateral rotation turns every postback into a 403 until your back office is updated.

Endpoints

RevoSurge uses local postbacks: one URL per event type. The path decides the event type — the event macro is recorded for cross-checking but is never used to classify the conversion, so a change to what your template expands to cannot silently reclassify our conversions.

GET/v1/pb/{partner}/registrationGET/v1/pb/{partner}/first-depositGET/v1/pb/{partner}/repeat-depositGET/v1/pb/{partner}/revenue
EndpointRecorded asreported_firstFire it when
/registrationregisterA player account is created — the first event carrying a player id
/first-depositdeposit1A deposit your system considers the player's first
/repeat-depositdeposit0Any subsequent deposit
/revenuepartner_revenueA revenue-share settlement event

All four take an identical parameter set — only the path differs — so you can register them from one template.

Two notes on how these are recorded:

  • first-deposit and repeat-deposit both store deposit, with your first-deposit claim kept as a flag rather than as truth. RevoSurge computes first-time deposits independently, and the difference between the two figures is free reconciliation.
  • revenue is stored as partner_revenue, not as GGR. It is the commission figure, which differs from operator GGR by the revenue-share rate; conflating them would be a units error.

WARNING

Do not register an "all deposits" postback alongside first-deposit and repeat-deposit — every deposit would be counted twice.

Do not register a global postback (one URL with the event type in a macro). The event type is already in the path. If we add an event type later, we will send you a new URL for it.

Parameters

Every endpoint accepts the same parameters. Map your back office's macros onto these names — the names on the left are the contract, the macro syntax on the right is yours.

ParameterRequiredDescription
kYesYour postback key (see Authentication)
click_idYes*The RevoSurge click id, echoed back from the sub-parameter it was delivered in (commonly {sub1}). The only campaign-level attribution anchor
user_idYes*Your pseudonymous player id. The key that stitches a player's events together
ctxRecommendedThe RevoSurge delivery context, echoed back (commonly {sub2}). Fallback attribution once the click-id window has passed
event_idRecommendedYour globally unique event id. Used as the deduplication key — see Deduplication
txidRecommendedTransaction id. Second choice for the deduplication key
eventRecommendedYour own event-type macro. Recorded as a cross-check against the endpoint path, never used to classify
amountDeposits & revenueThe monetary value, as a decimal. Signed — see How values are interpreted
tsRecommendedEvent time as unix milliseconds
countryOptionalPlayer country
hash_id, hash_nameRecommendedYour link/account taxonomy identifiers
source_id, source_nameRecommendedYour traffic-source taxonomy identifiers

* At least one of click_id or user_id must be present. A postback with neither cannot be addressed to anything and is dropped (with a 200 — see Responses).

Parameters not listed here are kept verbatim on the stored event, so a macro you add later still reaches us without a change on our side.

Why we ask for the taxonomy fields

hash_id, hash_name, source_id and source_name are typically constants for a single-account integration, so they attribute nothing today. We ask for them anyway because:

  1. A value that is not ours means traffic has been miswired — either someone else's traffic is pointed at our URL, or ours is registered under another account. This is monitored and alerted on.
  2. They become meaningful the moment the integration grows past one link.
  3. Adding a macro later means re-registering the URLs in your back office. Sending them from day one is far cheaper.

Example

URL template

Register these four URLs, substituting your partner slug and key. The {...} values are your back office's macro names — the example below uses the common sub1/sub2 convention.

text
https://mmp.revosurge.com/v1/pb/{partner}/registration?k=<KEY>&click_id={sub1}&ctx={sub2}&event={event}&user_id={user_id}&event_id={event_id}&txid={transaction_id}&amount={amount}&ts={date}&country={country}&hash_id={hash_id}&hash_name={hash_name}&source_id={source_id}&source_name={source_name}

https://mmp.revosurge.com/v1/pb/{partner}/first-deposit?k=<KEY>&…same query string…

https://mmp.revosurge.com/v1/pb/{partner}/repeat-deposit?k=<KEY>&…same query string…

https://mmp.revosurge.com/v1/pb/{partner}/revenue?k=<KEY>&…same query string…

A fired postback

bash
curl -sS -o /dev/null -w '%{http_code}\n' -G \
  "https://mmp.revosurge.com/v1/pb/{partner}/first-deposit" \
  --data-urlencode "k=$REVOSURGE_POSTBACK_KEY" \
  --data-urlencode "click_id=8f1c2d5e-4a7b-4c31-9e0d-6b2f7a1c93de" \
  --data-urlencode "ctx=ctx_9931" \
  --data-urlencode "event=first_deposit" \
  --data-urlencode "user_id=p_88213" \
  --data-urlencode "event_id=evt_5f3c9a10" \
  --data-urlencode "txid=txn_554433" \
  --data-urlencode "amount=100.00" \
  --data-urlencode "ts=1718280000000" \
  --data-urlencode "country=BR"
text
https://mmp.revosurge.com/v1/pb/{partner}/first-deposit
  ?k=<KEY>
  &click_id=8f1c2d5e-4a7b-4c31-9e0d-6b2f7a1c93de
  &ctx=ctx_9931
  &event=first_deposit
  &user_id=p_88213
  &event_id=evt_5f3c9a10
  &txid=txn_554433
  &amount=100.00
  &ts=1718280000000
  &country=BR

Responses

The write is confirmed to durable storage before we answer. A 200 therefore means the conversion is recorded, not merely received.

StatusBodyMeaningResend?
200{ "status": "ok" }Stored and confirmedNo
200{ "status": "ignored" }The payload carried no usable identity, so there is nothing to recordNo — a resend would be identical
503{ "status": "unavailable" }We could not confirm storageYes — this is the only case where a resend helps
403Bad key, or a source IP outside the allowlistNo — fix the configuration first

IMPORTANT

We never return 4xx for a payload problem. A 4xx is commonly read as permanent and can lead to the postback being disabled altogether — and the raw URL is already preserved in our request log, which is where a malformed postback actually gets diagnosed. If a postback is being dropped, you will hear it from us, not from the status code.

Retry policy we expect

  • Retry on 503, on a connection error, and on a timeout.
  • Use exponential backoff, and carry the same event_id on every attempt so the retry collapses onto the original record.
  • Do not retry on 200 or 403.

Deduplication

Every postback is reduced to a dedup key, and a resend that produces the same key collapses onto the same record instead of creating a second one. The key is chosen in this order:

  1. event_id, if present.
  2. txid, if event_id is absent.
  3. Otherwise a hash of the whole query string, prefixed h:.

The fallback is deliberately conservative: it collapses only a byte-identical resend (parameter order aside). It is a safety net, not a substitute for an id.

IMPORTANT

Send a globally unique, stable event_id, and repeat it verbatim on every retry. Without one, a retried revenue event is indistinguishable from a second, genuine revenue event — and a retried deposit inflates settlement. event_id must be unique across event types, not just within one.

How values are interpreted

FieldRule
amountParsed as a signed decimal. Negative values are valid — under a revenue share, a losing period for the operator is a negative income event. The raw string is always preserved alongside the parsed value, so a parse failure never loses the number
CurrencySettlement is in USD; no currency macro is expected. If you send a currency parameter with anything other than USD, it is recorded and raised as a contract change rather than silently converted
tsUnix milliseconds. We do not auto-detect seconds-vs-milliseconds: the contract says milliseconds, so a value in seconds is a signal that something drifted, and guessing would hide it. A time outside a plausible window is stored as unset, with the raw string kept
Event ageEvents older than 30 days or more than 60 minutes in the future are recorded and flagged, never rejected. Under a lifetime revenue share, revenue for an old player is exactly what the integration is for
Unsubstituted macrosA value that arrives as a literal macro (e.g. click_id={sub1}) is treated as absent, not as a string. See below

Unsubstituted macros

A URL pasted into an email or a ticket gets fetched by link scanners with the macros still literal. Left untreated, click_id={sub1} is a non-empty string and would manufacture a conversion that looks entirely legitimate — so:

  • A literal macro in click_id or user_id drops the postback (200 ignored).
  • A literal macro in any other parameter costs only that field; the rest of the event is recorded, and the literal value is kept verbatim for diagnosis.

Verifying an integration

Before switching real traffic on, confirm all four behaviours:

bash
KEY="<your-key>"

# 1. Happy path — expect 200 {"status":"ok"}
curl -s "https://mmp.revosurge.com/v1/pb/{partner}/registration?k=$KEY&click_id=test-click-001&user_id=p_test"

# 2. Wrong key — expect 403
curl -s -o /dev/null -w '%{http_code}\n' "https://mmp.revosurge.com/v1/pb/{partner}/revenue?k=WRONG"

# 3. No identity — expect 200 {"status":"ignored"}
curl -s "https://mmp.revosurge.com/v1/pb/{partner}/registration?k=$KEY"

# 4. Unsubstituted macro — expect 200 {"status":"ignored"}
curl -s "https://mmp.revosurge.com/v1/pb/{partner}/registration?k=$KEY&click_id=%7Bsub1%7D"

Then send one real test conversion through your back office and ask us to confirm, field by field. Three things are worth checking explicitly, because each one produces clean-looking but wrong data if it is off:

  1. The unit and timezone of ts — a seconds-vs-milliseconds mix-up parses fine and lands decades away.
  2. Whether event_id actually arrives — we can measure how often the hash fallback is used, and that number should be zero.
  3. The real values of hash_id and source_id — the drift alert stays silent until we record your baseline.