Product
Publishers
Advertisers
Networks
Help
Pause animations
Browse help topics
Reference PublisherNetwork

How to answer a postback, timeouts and retries

Updated

View as Markdown

Store the postback, answer with any 2xx status, then credit the user. We judge your answer by its status code alone: a 2xx ends the delivery, a timeout, a 5xx or a 429 gets a quick retry on publisher postbacks, and any other answer is final.

See also: Signed postbacks

On this page

What we do with your answer

Your server’s answerWhat we recordDo we try again?
Any 2xx, such as 200 or 204sentNo
A 5xx, such as 500 or 503failed, if every try failsYes, on publisher postbacks
429failed, if every try failsYes, on publisher postbacks
Any other 4xx, such as 400, 401 or 404failedNo
No answer in time, or no connection at allfailed, with the errorYes, on publisher postbacks

We never judge the body of your answer. It may show under Response in Flight Recorder, but a 200 that says “error” in its body still counts as sent, and a sent delivery means your server answered, not that it credited anyone.

Timeouts and retries

  • Publisher postbacks get up to three tries. That covers the Offer API, the Top Offers Feed, Offer Links and the Hosted Offerwall. The second and third tries follow a fraction of a second after the one before.
  • All the tries share one time limit of 20 seconds at most. A server that hangs on the first try uses it up, so a slow answer gets no second try. Answer within a few seconds.
  • Network postbacks are sent once. There is no retry on a timeout, a 5xx or a 429.
  • Nothing is resent later on its own. After the last try, the delivery stays failed.

Answer first, then credit

Do the slow work after you answer. In order:

  1. Check the verifier. If it doesn’t match, answer 401 and credit nothing. A 401 is final, so we don’t send it again.
  2. Store the postback under its action_id and status together. If that pair is already stored, answer 200 and stop: it’s a repeat.
  3. If storing fails, answer 500. On publisher postbacks we try again.
  4. Answer 200.
  5. Credit the user on completed, deduct on reversed, from what you stored, in a queue or a background job.

Retries mean the same postback can reach you twice. If your server credits the user and then answers 500, we send it again. Storing first and checking the pair makes the second copy harmless. Dedupe on action_id alone and you drop the reversal of a conversion you already credited, because a reversal repeats the original action ID.

JavaScript
// Example receiver for Pebble Rewards (Express).
app.get("/afos", async (req, res) => {
  if (!verified(req)) return res.sendStatus(401);
  const { action_id, status } = req.query;
  let isNew;
  try {
    // Unique on (action_id, status): a repeat inserts nothing.
    isNew = await db.insertOnce(action_id, status, req.query);
  } catch {
    return res.sendStatus(500); // publisher postbacks are retried
  }
  res.sendStatus(200);
  if (isNew) queue.push({ action_id, status });
});

verified() is the signature check in Verify a signed postback with HMAC-SHA256. Point your postback URL at the endpoint that answers, not at a redirect.

Find a failed delivery

Publishers: open Reporting, then Flight Recorder, and set Delivery to failed. Open a conversion: Your postback delivery shows when we tried (Attempted), the HTTP status your server returned, the Host, Path and Masked URL we called, and the Error when there was no answer. Copy request copies the URL and its parameters, with secrets masked.

Networks: Reporting, then Flight Recorder has the same Delivery filter. Open a postback and read Network Delivery Response: Attempted, Status, HTTP, Host, Path, Masked URL, Error and Response.

What Reporting, Flight Recorder shows when you open a conversion. A failed delivery shows the reason on the last step.

Two delivery results aren’t about your answer at all:

  • failed with an error about a postback secret means nothing was sent: publisher postbacks are never sent unsigned. Create the secret under Postbacks.
  • skipped_no_url means no postback URL matched the conversion. How to set up a postback URL covers which row takes which step.
Reversal. A conversion taken back after it was reported, by the advertiser or after our traffic checks. We take back its payout and send the publisher a reversal postback.What is a reversal?
Action ID. The ID of one conversion, sent as action_id on its postback. A reversal repeats the same ID.What is an action ID?

Support

Still stuck? Write to us.

One address for every question: hello@affiliateos.ai. Put the details from this list in your first message so we can find the click or conversion without asking you for them again.

Put these in your message

  1. 01The email you sign in with
  2. 02Your role: publisher, advertiser or network
  3. 03The offer ID
  4. 04The click ID or action_id
  5. 05The time it happened, with your time zone
  6. 06What you expected to happen

Looking for a reward in an app? Ask that app's support. It credits your reward, so only it can see your balance.

Search help