
Publisher docs
Integrate your app with 
The same integration guide publishers see inside the dashboard.
Macro reference
Every macro, what it carries on each of the four channels, and its dedupe role.
All macros
Every macro LootHQ substitutes into your template URL, what it carries on each of the four channels that can call you, and which ones identify a credit. Generated from the same table the production postback firer reads, so it cannot drift from what actually arrives.
Four things ever call your URLs: a hosted-wall conversion approval, an Offers API conversion approval, and a prize redemption, all three on your primary URL, plus a reversal on the separate reversal URL. Each is a column below.
A macro with no value on a channel arrives present and EMPTY, never missing
The param is still in the query string with nothing after the =. So points ?? payout and points != null both pick the empty string, and Number("") quietly credits 0. Test for "", not for null. A dash in the table below means exactly this case.
Every macro we substitute. All 15 macros.
| Macro | Hosted wall | Offers API | Prize | Reversal |
|---|---|---|---|---|
| {user_id}{sub_id}Your own user id: the sub_id you passed to the wall or the Offers API feed. Use it to credit the right account. Sent on every channel, reversals included. | your sub_id | your sub_id | your sub_id | your sub_id |
| {transaction_id}{click_id}The click id behind this credit (the conversion's own id when there is no click, e.g. a survey completion). It repeats across the goals of a MULTI-GOAL offer, so dedupe credits on the ({transaction_id}, {event_id}) pair, never on it alone. A reversal carries the same id, which is how you join it to the credit it cancels; on that channel dedupe on {event_id} instead. | the CLICK id, which repeats across goals | the CLICK id, which repeats across goals | prize_<id>, unique per credit | the ORIGINAL conversion's click id |
| {payout}{amount}USD value of this credit for your user, already net of your placement margin. On the reversal URL: the full USD value credited at approval, now being reversed. Never negative; a reversal is never signalled by sign. On the wall channel, credit {points} instead, which is this value in your own currency. | user payout, USD | user payout, USD | face-value USD | full credited USD |
| {publisher_payout}{pub_payout}USD you earn on this conversion, before your own placement margin. The one money macro about you rather than your user; the difference between it and {payout} is your margin, so take care before forwarding both to your own users. Empty on prize redemptions, which earn you nothing. Never negative. | your payout, USD | your payout, USD | empty | your payout, reversed |
| {points}Amount to credit in YOUR currency. Hosted wall: this conversion's coins multiplied by your points-per-coin rate. Offers API: {payout} multiplied by the reward rate on the placement, and empty until you set one; use {payout} there in the meantime. | coins × your rate | payout × your rate; empty with no rate | coins × your rate | full credited points |
| {coins}LootHQ coins behind this credit, at 1,000 coins per USD of user payout (on the reversal URL: the coins reversed). Empty on Offers API postbacks, which have no coin step, even when the placement has a reward rate: {points} is priced straight from {payout} there. | coins for this conversion | empty | coins redeemed | coins reversed (0 on Offers API) |
| {offer_id}The LootHQ offer id, on every conversion and reversal postback. The stable key: join your reporting and any hold policy on it, never on {offer_name}, which is mutable. Empty on prize redemptions, which no single offer produced. Need the offer image too? GET /api/v1/conversions returns name and image inline per conversion. | the offer id | the offer id | empty | the offer id |
| {offer_name}{offer_title}The offer's display name at dispatch time, URL-encoded (e.g. "Lucky7"). Print it in your completions feed; join on {offer_id}, since names can change. Empty on prize redemptions. | the offer name | the offer name | empty | the offer name |
| {currency}Currency of this credit: your own currency name (e.g. "gems") whenever {points} is the amount you credit, which is every hosted-wall postback and an Offers API postback from a placement with a reward rate; "USD" on Offers API postbacks with no rate, where {payout} is the amount. Empty on the reversal URL. | your currency name | "USD"; your currency name with a rate | your currency name | empty |
| {status}Always "approved" on the primary URL and always "reversed" on the reversal URL, with no third value. A primary-URL handler never sees a reversal or a negative amount, so do not write code that waits for one; sharing one endpoint across both URLs? Branch on this. | "approved" | "approved" | "approved" | "reversed" |
| {reason}reversal URL onlyReversal postback only. Why the conversion was reversed (chargeback, fraud, advertiser void, manual, …). | empty | empty | empty | why it was reversed |
| {event_id}Which event this delivery is about, per channel. On conversion postbacks (both channels): the goal id being credited ("signup", "deposit", or "conversion" on a single-goal offer); the ({transaction_id}, {event_id}) pair is the per-credit dedupe key. On the reversal URL: a fresh UUID per reversal delivery, and the reversal dedupe key. Empty on prize redemptions, whose {transaction_id} is already unique. | goal/event id ("signup", …) | goal/event id ("signup", …) | empty | fresh UUID per delivery, the dedupe key |
| {original_event_id}{reversed_event_id}reversal URL onlyReversal postback only. The goal id of the credit being reversed ("signup", "deposit", or "conversion" on a single-goal offer) — the same value {event_id} carried on the approval postback that credited it. Pair it with {transaction_id} to find the exact credit to claw back; on a multi-goal offer that pair is the only thing that identifies which goal was reversed. Still dedupe reversals on {event_id}, which is this delivery's own UUID. | empty | empty | empty | the reversed credit's goal id |
| {event_name}{goal_name}Display name of the goal being credited on a multi-goal offer ("Reach level 10", "Day 3 check-in"), URL-encoded. Empty when the offer has no per-goal names, which is normal on single-goal offers, and on prize redemptions and reversals. Print it in your feed; join and dedupe on {event_id}, since names can change. | goal display name, may be empty | goal display name, may be empty | empty | empty |
| {source}"prize" on a leaderboard Prize Coin redemption, empty on every other postback. Branch on it equalling "prize", never "offer", which is a value that is never sent. | empty | empty | "prize" | empty |
Which params identify a credit
On your primary URL, the ({transaction_id}, {event_id}) pair. On the reversal URL, {event_id} alone, because there {transaction_id} is the original conversion and repeats. The full per-channel reasoning, and what happens if you get it wrong, is in Dedupe keys, per channel.
The shipped default template, sample handlers in three languages and the retry schedule are on Postbacks. Reversal-channel specifics are on Reversals.