Skip to content
LaunchOfferwall

Guide

How offerwall postbacks work, from click to credited user

Postbacks are how an offerwall knows a user finished an offer. Get them right and users are paid reliably; get them wrong and you lose money or pay twice. Here is the whole chain.

What a postback is

A postback is an HTTP request one server sends to another to report a conversion. It is also called a server-to-server (S2S) callback, a server postback or a conversion callback. Unlike a tracking pixel, it does not depend on the user's browser: when the advertiser's tracking platform records a qualifying event, its server calls a URL you gave it, with details of the conversion in the query string or body.

An offerwall involves two postbacks. The incoming postback travels from the partner network to the offerwall network and says this click converted. The outgoing postback travels from the offerwall network to the publisher and says credit this user. The click ID is what links them.

Step 1: the click ID

Everything starts when a user taps an offer. The offerwall issues a click ID and appends it to the advertiser's tracking link, usually in a sub-ID parameter such as sub1 or subId1. The partner stores it and returns it, unchanged, in the postback.

A good click ID identifies the network, the publisher app, the user and the offer, and cannot be forged. The safest design is a signed token: the claims are encoded in the ID and signed with a secret key, for example with HMAC-SHA256. When the postback returns, the network verifies the signature before trusting anything in it. A forged or altered click ID fails the check and never becomes a conversion. Give tokens an expiry too; a conversion arriving months after the click is more likely abuse than a late user.

Some partners cap sub-ID length. In that case the network can send a short random ID and keep the signed token on its side, looking it up when the postback arrives. LaunchOfferwall does this automatically for impact.com.

Step 2: the incoming postback URL

The network gives each partner a postback URL to call. The partner replaces macros in it, placeholders in braces such as {sub1} or {transaction_id}, with real values when it fires. Macro names differ between platforms, which is why each integration needs its own URL. For example, an Everflow postback might use {sub1} for the click ID, {transaction_id} for the transaction and {revenue} for the payout, while Affise uses {sub1}, {action_id}, {sum}, {status} and {goal}.

At a minimum the incoming postback needs the click ID and a transaction ID that is unique per conversion. Useful extras are the payout, so you can credit the actual amount, a status, so you can handle pending and reversed conversions, and a goal or event identifier for multi-event offers.

Protect the endpoint. Include a secret key in the URL and compare it on every call, store only a hash of the key, and let tenants rotate it if it leaks. Some networks also restrict calls to the partner's server IPs.

Step 3: receive fast, process safely

Partners expect a quick 200 OK. If the endpoint is slow or errors, many partners retry, and some give up. So the receiving endpoint should do the minimum: check the key, store the raw request exactly as it arrived, put the event on a queue, and answer. Conversion logic runs afterwards, in a background worker that can retry safely.

Storing the raw request matters more than it sounds. When a partner disputes a number, or a bug needs replaying, the original request is the only source of truth.

Step 4: deduplicate on transaction ID

Partners send duplicates. They retry when your response is slow, operators fire test postbacks, and queues deliver messages more than once. The defence is a uniqueness rule in the database: one conversion per source and transaction ID. Insert with that constraint and treat a conflict as already processed. That makes the whole pipeline idempotent, so you can retry anything without paying twice.

Scope the rule to the source (the partner connection). Two different partners can legitimately use the same transaction ID.

Step 5: statuses, pending and reversals

Many partners report a conversion more than once as its status changes: pending when the event happens, approved after review, reversed if the advertiser rejects it. Map each partner's status values to a small set, approved, pending and reversed, and decide what pending means for your network. Crediting users on pending is a better experience; waiting for approval is safer. Make it a per-partner setting.

A reversal must undo the original conversion, found by the same source and transaction ID, and tell the publisher so the user's reward can be deducted. A reversal for a conversion you never recorded should be logged and ignored.

Step 6: work out the reward

With a verified click and a fresh transaction, the worker calculates the money. Take the payout from the postback if the partner sent one, otherwise from the goal or offer. Apply the publisher's revenue share, then convert their share to the app's virtual currency.

Do this in integers. Store money as micros (millionths of a dollar) and shares as basis points (10,000 = 100%). Floating-point maths drifts by fractions of a cent per conversion, which adds up, and makes reconciliation with partners painful.

This is also the moment to run conversion-level fraud checks, such as a conversion arriving seconds after the click, or a user converting far more often than a person could. Suspicious conversions should be held for review rather than paid.

Step 7: the outgoing publisher postback

Finally the network calls the publisher's postback URL. Publishers configure it with macros too. On LaunchOfferwall these include {user_id}, {transaction_id}, {reward}, {payout}, {status}, {offer_id}, {offer_name}, {event_id}, {event_name}, {user_ip}, {country} and {hash}, in either {curly} or [BRACKET] form.

The publisher must be able to tell a real postback from a forged one, because anyone who discovers the URL could otherwise credit themselves. The standard approach is a per-app secret and a hash. LaunchOfferwall sends hash = sha256(user_id + offer_id + transaction_id + secret); the publisher recomputes it and rejects any mismatch. Our developer page has working Node.js and PHP code.

Publishers should also store the transaction ID and ignore repeats, for the same reasons as above.

Step 8: retries with backoff

Publisher servers go down, deploy, rate-limit and time out. The network should treat anything other than a 2xx response within a sensible timeout as a failure and retry with exponential backoff: wait a minute, then two, then four, up to a ceiling such as an hour, and keep going for long enough to survive an outage. LaunchOfferwall retries for 72 hours, recording each attempt's status and response so either side can see what happened.

Schedule each retry as a fresh delayed message rather than relying on a queue's built-in retry count, so a long outage never exhausts the retries. Add a periodic sweep that re-queues any delivery whose retry time has passed, in case a message is ever lost.

Testing your postbacks

Before going live with a partner or publisher, run through a short checklist.

  • Click an offer and confirm the click ID appears in the partner's click log.
  • Fire a test conversion and confirm it is recorded once, with the right payout and reward.
  • Fire the same postback again and confirm it is treated as a duplicate.
  • Send a reversed status and confirm the publisher receives a negative postback.
  • Change one character of the click ID and confirm the conversion is rejected.
  • Point a publisher postback at a server that returns 500 and confirm retries arrive with increasing gaps.

Common mistakes

  • Putting the click ID in a parameter the partner does not pass back.
  • Deduplicating on click ID instead of transaction ID, which breaks multi-event offers.
  • Doing heavy work before answering the partner, causing timeouts and duplicate retries.
  • Ignoring reversals, so fraudulent conversions stay paid.
  • Publishers skipping hash verification because the URL seems secret.
  • Using floating-point numbers for money.

Get a postback pipeline that is already built