Affiliate Analytics

Postback vs API: How Affiliate Conversion Tracking Really Works

62%+18%

An affiliate click leaves a strange gap in your data. Someone clicks your link, disappears onto the merchant's site, and — maybe — buys something three days later from a different device. The commission shows up in your network dashboard a week after that, as a lump sum with no memory of which of your pages sent the buyer. That gap between the click you can see and the commission you can't connect to it is the single reason most affiliate sites can't tell you their real earnings per page. Closing it is what conversion tracking does, and server-side, there are exactly two ways to do it: a postback, or an API.

Postback vs API affiliate conversion trackingTwo ways the sale gets back to youPostback — the network pushesSale happens on the merchantNetwork fires your postback URLYour endpoint logs it — livepush · per-sale · near-instantAPI — you pullYour server calls the conversions APINetwork returns conversions + SubIDYou match SubID → click → pagepull · batched · every hour or dayBoth rely on one thing: the SubIDA unique ID on every outbound link that carries the page it came from —so each returned commission lands on the right page’s EPC.
Postback pushes each conversion to you the moment it clears; an API lets you pull them on a schedule. Both are useless without a unique SubID on the outbound link — that’s what ties the commission back to the exact click and page.

The click-to-commission gap

Everything upstream of the click, you can measure yourself. Which page, which link, which placement — that's your side of the fence, and a good affiliate tracking setup captures all of it. Everything downstream — did they buy, how much, how much commission — happens on the merchant's servers, where you have no visibility at all.

The network is the only party that sees both sides: it knows the click came from you (because your ID rode along on the link) and it knows the sale happened (because the merchant told it). Conversion tracking is simply the pipe that carries that reconciled fact — this sale belongs to this click — from the network back to you. Get that pipe working and the click-to-commission gap closes; skip it and you're left doing what most affiliates do — reconciling a spreadsheet of network payouts against a guess about which pages earned them.

There are two ways to build the pipe. The difference is just who calls whom.

Postback: the network pushes the sale to you

A postback (also called a server-to-server or S2S postback) flips the usual direction: instead of you asking the network for data, the network calls you the instant a conversion is confirmed.

It works in three moves:

  1. You put a unique ID — your SubID — on every outbound affiliate link. This ID encodes what you care about: at minimum the page, ideally the placement too.
  2. You register a postback URL on your own server with the network, with placeholders for the values you want back.
  3. When the sale clears, the network fires that URL, substituting in your SubID and the commission. Your endpoint records it.

The registered URL looks like this — the {...} tokens are placeholders the network fills in:

https://track.yoursite.com/postback
  ?subid={SubId1}
  &order_id={ActionId}
  &amount={Payout}
  &status={Status}

And the receiver is about as much code as it sounds — read the query, write the row:

// app/postback/route.ts  (edge or node)
export async function GET(req: Request) {
  const u = new URL(req.url);
  const secret = u.searchParams.get("k");
  if (secret !== process.env.POSTBACK_SECRET) return new Response("no", { status: 403 });

  await recordConversion({
    subid: u.searchParams.get("subid") ?? "",     // carries the page
    orderId: u.searchParams.get("order_id") ?? "",
    amount: Number(u.searchParams.get("amount") ?? 0),
    status: u.searchParams.get("status") ?? "",    // pending | approved | reversed
  });
  return new Response("ok"); // networks expect a fast 200
}

On Impact specifically, you'll find this under your tracking settings as a server-to-server postback; you pass your value in SubId1 on the click, and Impact returns it (as SubId1) along with the ActionId, Payout, and action State when it fires the postback. Add a shared secret to the URL so nobody can forge conversions, and return a fast 200 — networks retry slow or failing endpoints and eventually give up.

The appeal is that it's real-time and per-sale. The moment a commission is registered, you know — no polling, no waiting for a report to refresh. Because it's a server-to-server call keyed on your SubID rather than a browser cookie, ad blockers and third-party-cookie loss don't touch it, which is the accuracy win server-side tracking is genuinely good for.

The catch: a postback captures a conversion at the status it had when it fired — usually "pending." Commissions get approved, reduced, or reversed weeks later, and the postback that told you about the sale won't tell you it was later refunded. Which is exactly what the second method is for.

API: you pull the sales from the network

An API reverses it again: your server calls the network on a schedule and pulls down the conversions itself.

// runs on a cron — hourly, or nightly for reconciliation
const res = await fetch(
  "https://api.impact.com/Mediapartners/ACCOUNT_SID/Actions?" +
    new URLSearchParams({ StartDate: since, PageSize: "1000" }),
  { headers: { Authorization: "Basic " + btoa(`${SID}:${TOKEN}`), Accept: "application/json" } }
);
const { Actions } = await res.json();
for (const a of Actions) {
  await upsertConversion({
    subid: a.SubId1,          // same key as the postback
    orderId: a.Id,
    amount: Number(a.Payout),
    status: a.State,           // now the *current* status, not a snapshot
  });
}

Because you control when it runs and it returns the current state of every action, an API pull is the tool for the jobs a postback can't do: backfilling history when you first set tracking up, reconciling pending commissions against their final approved or reversed amounts, and covering networks that don't offer postbacks at all. The trade-off is latency and effort — you only know as often as you poll, you have to store a cursor so you don't miss or double-count actions, and every network's API is its own little adventure in authentication and pagination.

Postback vs API, side by side

Postback (push)API (pull)
DirectionNetwork → youYou → network
TimingReal-time, per saleScheduled (hourly/nightly)
Best atLive earnings, instant signalBackfill, reconciliation, final status
Status accuracySnapshot at fire time (usually pending)Current status every pull
SetupRegister one URL + a receiverAuth, pagination, a cursor, a cron
Fails whenYour endpoint is down (retries, then lost)You poll too rarely or miscount actions
Cookies?Cookieless (S2S)Cookieless (S2S)

Read that table and the answer to "which one?" stops being either/or. Use both. Let postbacks give you the live number the moment a sale lands, and run an API sweep nightly to true everything up against final, locked earnings. Postback tells you something happened; the API tells you what it was ultimately worth.

"Do I just use wecantrack?"

Probably the most-searched version of this question pairs it with a tool — usually wecantrack — that does the postback-and-API plumbing across dozens of networks so you don't have to. Here's the honest take, because it's a real trade and not a gotcha.

A middleware like that genuinely saves you the per-network setup, and if you're running twenty networks that's a lot of little integrations to not maintain. But you're paying a subscription, and — the part worth thinking about for a data company's own site — your revenue data now flows through a third party's servers before it reaches you. If you run a handful of networks, pointing their postbacks straight at your own endpoint (the twenty lines above) keeps the whole loop first-party and the data unambiguously yours. If you run dozens, the fee may buy back more time than it costs. The mechanism underneath is identical either way; you're only deciding who operates the pipe.

The one thing both methods depend on

Notice what postback and API have in common: neither works without a unique SubID on the outbound link, and that SubID is only as useful as what you encode in it. A conversion that comes back tagged SubId1=xyz is worthless if xyz doesn't tell you which page and placement produced the click. Get this right — a consistent, parseable ID that carries the page — and both pipes light up. Get it wrong and you'll have perfectly plumbed tracking that reports total conversions and nothing about where they came from. This is the same discipline behind network tracking IDs and SubIDs in every tracking method; server-side just raises the stakes, because now it's the join key for your entire revenue dataset.

The payoff: per-page EPC you can trust

Here's why any of this is worth the trouble. Once conversions flow back keyed on a SubID that carries the page, you can finally join them to the clicks you already log — and the moment click data and commission data share a key, per-page numbers become real. Earnings by page. EPC by placement. Revenue per visitor by cluster. The metrics that tell you which content to double down on and which to cut — none of which GA4 can compute, because it never sees your commissions.

That's the whole point of closing the click-to-commission gap: not tidier tracking for its own sake, but an EPC number you'd actually bet a content decision on.

Related reading