Skip to content
Docs

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.

text
https://track.yourbrand.com/p?click_id={click_id}&goal=sale&txn_id={order_id}&amount={amount}&currency=USD&security_token=TOKEN

Notes that save support tickets:

  • The advertiser substitutes the braces with its own values; click_id is 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 as sub_id).
  • goal is the goal key, not its display name. Without it the offer's base goal is used.
  • txn_id is 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:

text
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 by conversion_id. With the same order id on several offers, add offer_id. reason is 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 cancelled with reason reversal (or reversal:<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 answers rejected (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. /reversal is 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.

FieldMeaning
typeurl (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, headersThe request. GET by default; POST/PUT/PATCH/DELETE with a body template are supported.
partner_id, offer_id, goal_idScope. Empty means "all".
event_scopeconversion (base goal only), goal (non-base goals), conversion_goal or all.
fire_oncreate, 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_statusesOnly fire for these statuses, for example approved only.
block_zero_payoutSkip conversions with a zero payout.
delay_secondsWait 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.

text
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 to DT_PB_CONCURRENCY (default 512) run at once. Private and loopback destinations are refused unless DT_ALLOW_PRIVATE_DESTINATIONS=1.
  • A failed attempt (network error, 5xx, 429 or 408) 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 a postback_disabled notification 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_result event 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:...}:

PresetEndpoint_config keys
capi:metaMeta Conversions API v19.0/{pixel_id}/eventspixel_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:googleGoogle Ads uploadClickConversionscustomer_id, access_token, developer_token, conversion_action_id, conv_datetime. Uses the click's gclid.
capi:tiktokTikTok Events API event/trackpixel_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_template to mmp:appsflyer, mmp:adjust, mmp:branch, mmp:singular or mmp:kochava (the partner page in the admin and Postbacks ▸ Send conversions to an MMP in the partner portal have a form for it; partner API GET /partner/mmp-templates, then POST /partner/postbacks with the preset and its credentials). Credentials go in headers._config like the CAPI presets: AppsFlyer app_id, dev_key, event_name; Adjust app_token, event_token, s2s_token; Branch branch_key, event_name; Singular sdk_key, platform, bundle_id, event_name; Kochava app_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.