Tracking guide
Postbacks and templates
Receiving postbacks from advertisers, firing postbacks to partners and ad platforms, CAPI presets, retries and logs.
There are two directions. Inbound postbacks come from advertisers and create conversions; they are covered in conversion tracking methods. Outbound postbacks are fired by Metrixed after a conversion, to a partner's tracker or to an ad platform. This page is about outbound postbacks and the templates they use.
Inbound templates, per advertiser
Give each advertiser a URL like the one below. In the advertiser portal the Pixels page shows the postback URL, copy-ready snippets and a tester for it.
https://track.yourbrand.com/p?click_id={click_id}&goal=sale&txn_id={order_id}&amount={amount}¤cy=USD&security_token=TOKEN
Notes that save support tickets:
- The advertiser substitutes the braces with its own values;
click_idis the value we appended to its landing URL (put{click_id}in the offer's destination URL, or in a parameter the advertiser's platform stores, such assub_id). goalis the goalkey, not its display name. Without it the offer's base goal is used.txn_idis what makes retries safe. Always send it.- Many platforms use their own parameter names. The parser accepts all common spellings (parameters), so a template copied from Everflow, TUNE or Trackier works as is.
- For CAKE, TUNE and Everflow style postback paths (
/aff_lsr,/pb,/conv) the aliases are accepted as well.
Reversals (refunds and chargebacks)
When an order is refunded or charged back, the advertiser calls the reversal URL once:
https://track.yourbrand.com/reverse?txn_id={order_id}&reason=refund&security_token=TOKEN
- Find the conversion by
txn_id(the order id sent with the postback) or byconversion_id. With the same order id on several offers, addoffer_id.reasonis optional free text kept with the status change. - It is authenticated exactly like the advertiser's postbacks (token, IP allow-list or HMAC signature), or with a tenant API key in
Authorization: Bearer. - An approved, pending, on-hold or flagged conversion becomes
cancelledwith reasonreversal(orreversal:<your text>). Cap windows, tier counters and customer-value ladders it counted on are released, an approved payout is reversed in the ledger, and partners who opted in get a reversal postback. - It is exactly once: sending it again answers
duplicate(already_cancelled) and changes nothing. A rejected conversion answersrejected(not_reversible_rejected). - The answer is always HTTP 200 with JSON
{"status":"reversed|duplicate|rejected|unmatched|error","conversion_id":"…","reason":"…"}, and every call shows in Logs, Postbacks in./reversalis an alias of/reverse, GET and POST both work.
The advertiser portal shows the URL with the advertiser's token on Pixels & postbacks.
Outbound postbacks
A postback is configured per partner (and optionally per offer and goal) and fires when a conversion is created or changes.
| Field | Meaning |
|---|---|
type | url (server call), iframe_pixel, image_pixel, javascript_pixel. Only url postbacks are fired by the worker; pixel types are rendered on pages. |
url_template, method, body_template, headers | The request. GET by default; POST/PUT/PATCH/DELETE with a body template are supported. |
partner_id, offer_id, goal_id | Scope. Empty means "all". |
event_scope | conversion (base goal only), goal (non-base goals), conversion_goal or all. |
fire_on | create, status_change, payout_change, reversal. reversal is opt-in: the postback fires when the advertiser reverses a conversion through the reversal URL (the status is cancelled, {status} expands to it), whatever allowed_conversion_statuses says. Partners tick Reversed by the advertiser in their portal; postbacks without it never hear about reversals except through an ordinary status-change postback that allows cancelled. |
allowed_conversion_statuses | Only fire for these statuses, for example approved only. |
block_zero_payout | Skip conversions with a zero payout. |
delay_seconds | Wait before the first attempt. |
retry_policy | {"schedule_seconds":[60,300,...]} overrides the retry ladder. |
Templates use the macro syntax from the macros reference: {click_id}, {payout}, {sub1}, {goal_name}, and modifiers such as {sub1|urlencode}, {click_id|md5}, {sub2|default:none} and fallback chains {idfa||gaid}. {param:foo} reads any raw inbound parameter. Unavailable macros expand to empty. Id macros such as {offer_id}, {partner_id} and {advertiser_id} send the numeric ids shown in the portals (the same values as in the redirect); use {offer_ulid}, {partner_ulid}, {advertiser_ulid} or {goal_ulid} when the receiver needs the internal API ids.
https://partner-tracker.example/postback?cid={sub1}&payout={payout}&status={status}&goal={goal_key}
Delivery, retries and health
- Requests time out after
DT_PB_TIMEOUT_MS(default 10 s); up toDT_PB_CONCURRENCY(default 512) run at once. Private and loopback destinations are refused unlessDT_ALLOW_PRIVATE_DESTINATIONS=1. - A failed attempt (network error,
5xx,429or408) is retried on the ladder 1 minute, 5 minutes, 30 minutes, 2 hours, 12 hours, then finalised as failed (dead letter). Every attempt is logged. - After
DT_PB_DISABLE_AFTER(default 20) consecutive final failures the postback is disabled and apostback_disablednotification is sent. - Logs: Insights, Logs, tab Postbacks out, shows the resolved URL, request, response code and body, latency, attempt number and next retry. The
postback_resultevent is published for each attempt (schema).
CAPI presets (ad platforms)
Set url_template to capi:meta, capi:google or capi:tiktok and the worker fills in the platform's endpoint, headers and JSON body. Credentials go into the postback's headers under the reserved key _config (it is never sent), and are read by the templates as {param:...}:
| Preset | Endpoint | _config keys |
|---|---|---|
capi:meta | Meta Conversions API v19.0/{pixel_id}/events | pixel_id, access_token, optional event_name (default Purchase). Sends fbc, fbp, IP and user agent, value and currency. event_id is the conversion id, which de-duplicates against browser events. |
capi:google | Google Ads uploadClickConversions | customer_id, access_token, developer_token, conversion_action_id, conv_datetime. Uses the click's gclid. |
capi:tiktok | TikTok Events API event/track | pixel_code, access_token, optional event_name (default CompletePayment). Sends ttclid. |
Other platforms (Snap, Microsoft, Pinterest, Reddit, X, LinkedIn) can be reached with an ordinary url postback and a body template today; dedicated presets are not shipped yet.
MMP templates
For apps measured by AppsFlyer, Adjust, Branch, Singular or Kochava:
- Inbound (the advertiser's MMP reports installs and events to us): the advertiser page in the admin
(Reversals and MMPs) and Pixels & postbacks ▸ Mobile measurement partners in the advertiser portal show the
postback URL to paste into the MMP's partner setup, with the MMP's own macros mapped onto
click_id,goal,txn_id,amount,currency, device ids and the security token, plus the click-id parameter the MMP attribution link (the offer URL) must carry. API:GET /mmp-templates?advertiser_id=,GET /advertisers/{id}/postback-setup,GET /advertiser/mmp-templates. - Outbound (send conversions to a partner's MMP): set the partner postback's
url_templatetommp:appsflyer,mmp:adjust,mmp:branch,mmp:singularormmp:kochava(the partner page in the admin and Postbacks ▸ Send conversions to an MMP in the partner portal have a form for it; partner APIGET /partner/mmp-templates, thenPOST /partner/postbackswith the preset and its credentials). Credentials go inheaders._configlike the CAPI presets: AppsFlyerapp_id,dev_key,event_name; Adjustapp_token,event_token,s2s_token; Branchbranch_key,event_name; Singularsdk_key,platform,bundle_id,event_name; Kochavaapp_guid,event_name. Event names may use macros such as{goal}.
Outbound webhooks
For your own systems use webhooks: signed JSON envelopes for conversion and status events, with the same retry ladder.