Appearance
Postback contract
A postback tells DataFlair Stats that one player did something: registered, made a first deposit, or made another deposit. You send one request for each event, from your server. DataFlair records it against the affiliate and the program.
Endpoint
text
GET or POST https://{stats-host}/api/postback/{program}/{token}Copy the full URL from the Stats app: open the program, go to Integrations, and find the Postback endpoint card. The card also shows the masked token and has the Generate token and Regenerate token buttons.
Both methods work. A POST sends a JSON body. A GET sends the same fields as query parameters, which suits operators that fire a URL pixel. DataFlair merges the query string and the body, so the field names are the same either way.
Send Accept: application/json on every request so errors come back as JSON.
Authentication
The {token} in the URL authenticates the request. Each program has its own token. It is 64 hexadecimal characters and is separate from the API key DataFlair uses to pull your reports.
- Treat the full URL as a secret. Send postbacks from your server. Do not put the URL in client-side code.
- If the token is wrong or missing, DataFlair answers
401. - Regenerate token in the app makes the old token stop working at once. Update your integration with the new URL.
Signed requests (optional)
A POST can carry a signature in place of the token in the URL. Use the URL without the token segment, /api/postback/{program}, and add two headers:
| Header | Value |
|---|---|
X-Postback-Timestamp | The current Unix time in seconds, as digits. |
X-Postback-Signature | The lowercase hexadecimal HMAC-SHA256 of {timestamp}.{raw request body}, with your postback token as the key. |
DataFlair rejects a timestamp more than 300 seconds away from its own clock. Signing is for POST only. A GET postback uses the token in the URL.
What you send
bash
curl -X POST "https://{stats-host}/api/postback/12/YOUR_TOKEN" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"affiliate_id": "AFF-00042",
"conversion_type": "ftd",
"postback_id": "pb_001",
"amount": 25.00,
"status": "approved"
}'bash
curl -G "https://{stats-host}/api/postback/12/YOUR_TOKEN" \
-H "Accept: application/json" \
--data-urlencode 'affiliate_id=AFF-00042' \
--data-urlencode 'conversion_type=ftd' \
--data-urlencode 'postback_id=pb_001' \
--data-urlencode 'amount=25.00' \
--data-urlencode 'status=approved'The request builder fills in these commands for you. It does not send them.
Fields
| Field | Type | Required | Meaning |
|---|---|---|---|
affiliate_id | string | yes | The DataFlair affiliate ID, for example AFF-00042. The affiliate must be approved for the program. aff_id is accepted in its place when the program has no field mapping. |
conversion_type | string | yes | One of registration, ftd, deposit. See Conversion types. |
postback_id | string | yes | Your unique id for this event. Up to 255 characters. See Idempotency. |
amount | number | no | The amount, zero or more. Defaults to 0. |
currency | string | no | A currency code, up to 8 characters. DataFlair stores it as you send it. |
player_id | string | no | Your internal player reference. Up to 255 characters. |
occurred_at | datetime | no | When the event happened in your system. DataFlair reports the conversion on this date when it is present. Without it, DataFlair uses the time it received the request. |
sub_id | string | no | The sub_id you received on the landing page. Up to 100 characters. Letters, digits, _ and - only. See Tracking links. |
tracking_id | string | no | The tracking_id you received on the landing page, in the form TL- followed by letters or digits. |
status | string | no | One of approved, pending, rejected, hold, adjusted. Defaults to approved. See Status values. |
kyc_status | string | no | The player's KYC state: pending, verified or rejected. |
kyc_verified | boolean | no | A shorter form of kyc_status. true means verified and false means pending. kyc_status wins when you send both. |
df_click_id | string | no | A DataFlair click id in the form dfc_ followed by 16 hexadecimal characters. Send it back as sub_id instead. |
DataFlair ignores any other field. It records the source IP address of the request itself.
What you get back
A new conversion:
json
{
"success": true,
"conversion_id": 42,
"commission_id": 17
}commission_id is null when no commission record was created.
A repeat of a postback_id DataFlair already has:
json
{
"success": true,
"duplicate": true,
"conversion_id": 42,
"commission_id": 17,
"message": "Postback already processed (idempotent)."
}Errors
Every error body has "success": false and an error code. A message describes it.
| Status | error | What caused it | What to do |
|---|---|---|---|
401 | unauthorized | The token is wrong, or the URL has no token and no valid signature. The message says which: Invalid postback token., No postback token in URL. Expected: /api/postback/{program}/{token}, or Invalid or expired postback signature. | Check the URL. Check that the token was not regenerated. |
404 | program_not_found | The program does not exist or is not active. | Check the program id. Ask the operator to activate the program. |
422 | validation_error | A field is missing or invalid. The errors object lists each field. | Fix the fields named in errors. |
422 | affiliate_not_found | The affiliate is not approved for this program. | Send the affiliate_id you received on the landing page. |
422 | tracking_link_not_found | The tracking_id is not valid for this program or affiliate. | Send the tracking_id you received, or leave it out. |
429 | none | You sent more than 60 requests in one second with the same token. The response has a Retry-After header. | Wait, then retry with the same postback_id. |
429 | none | The same postback_id arrived twice at the same moment. The message is Concurrent delivery of the same postback_id; retry shortly. | Retry with the same postback_id. |
5xx | none | A server error. | Retry with the same postback_id. |
A validation_error looks like this:
json
{
"success": false,
"error": "validation_error",
"message": "Request validation failed.",
"errors": {
"conversion_type": ["The selected conversion type is invalid."]
}
}Conversion types
| Type | Meaning |
|---|---|
registration | A player account was created. |
ftd | The player's first deposit. |
deposit | A later deposit. |
Postbacks carry these acquisition events only. DataFlair does not accept cashout in a postback. Withdrawals and revenue reach DataFlair through the Operator Reporting API, which DataFlair pulls.
Timeouts and retries
The rate limit is 60 requests per second for each token. When the URL has no token, the limit applies to each source IP address.
Retry a 5xx, a 429 and a timeout with the same postback_id. Do not retry a 401, a 404 or a 422 until you have fixed the cause. The Idempotency page explains why a retry is safe.
Test this
Check the endpoint, fire a test postback and replay a logged one from the Stats app. See Testing postbacks.