---
title: Postback parameters
description: Every parameter the postback URL accepts, every response it returns, and what to paste into your offer source's postback field.
updated: 2026-07-30
order: 1
related: [/concepts/attribution, /guides/missing-conversions, /guides/offer-sources]
---

A postback is a URL your offer source calls when someone converts. It is the only
way conversions get into PostbackX, and it needs no API key.

## The URL

```
https://postbacks.postbackx.com/postback?click_id={click_id}&payout={payout}
```

`GET` and `POST` both work. `POST` accepts either `application/json` or
`application/x-www-form-urlencoded`, using the same parameter names.

What you actually paste into your offer source depends on where it stored the
click id. If you appended it as `sub5` on your offer URL, that is what its macro
will be called:

```
https://postbacks.postbackx.com/postback?click_id={sub5}&payout={payout}&transaction_id={transaction_id}
```

The `{...}` parts are your offer source's own macros — it substitutes real values
when it fires. Every platform names them differently, so copy them from its
documentation, not from here.

## Parameters

Only `click_id` is required. Every alias below is accepted as an equal
alternative, because offer sources disagree about what these fields are called.

| Parameter | Aliases | Required | Description |
| --- | --- | --- | --- |
| `click_id` | `aff_sub` | Yes | The click this conversion belongs to — the value PostbackX put into your offer URL. |
| `payout` | `amount` | No | Revenue for this conversion, as a decimal. Defaults to `0`. |
| `transaction_id` | `txn_id`, `order_id` | No | The offer source's own id for the conversion. Used to recognise repeat deliveries. |
| `event_name` | `event` | No | Which conversion action fired, e.g. `lead` or `purchase`. Falls back to the campaign's default event. |
| `sub1` … `sub5` | | No | Pass-through values, stored on the conversion for your own reporting. |
| `adv1` … `adv10` | | No | Advertiser custom parameters, forwarded to Facebook's Conversions API to improve match quality. |

> Any other parameter you add is stored on the conversion as well. Offer sources
> each have their own extra fields, so rather than maintain a list of them,
> PostbackX keeps whatever it is given.

## Responses

The status codes are worth reading before you go looking for a bug, because two of
them are deliberately not errors.

| Status | Meaning | Body |
| --- | --- | --- |
| `200` | Recorded. | `success: true` with `conversion_id`, `click_id`, `processing_time_ms` |
| `200` | Already recorded — a duplicate delivery. | `success: true`, `duplicate: true` |
| `202` | Accepted, queued, and will be processed shortly. | `success: true`, `accepted: true` |
| `400` | No `click_id`, or a body that could not be parsed. | `success: false` with `error` |
| `404` | That click id does not exist. | `success: false` |
| `410` | The click is more than 90 days old. | `success: false` |
| `500` | Something failed on our side. | `success: false` |

### Why duplicates and outages return 2xx

Most offer sources treat any non-2xx response as a failure and retry — some for
days. That behavior is useful when a postback genuinely did not arrive, and
harmful when it did.

So a duplicate returns `200`: the conversion is already recorded, the retry has
served its purpose, and there is nothing to gain from another attempt. And if the
database is briefly unreachable, the postback is queued and answered `202` rather
than failing — the conversion is safe, and telling the offer source otherwise
would produce a retry storm on top of an outage.

Treat `200` and `202` alike: the conversion is accounted for.

## Duplicate detection

A conversion is considered a duplicate when its **click id, transaction id and
event name** all match one already recorded.

This is why `transaction_id` is worth sending even though it is optional. With it,
repeat deliveries of the same conversion collapse into one, and two genuinely
different sales on the same click stay separate. Without it, PostbackX cannot tell
those two situations apart, and counts them as one conversion.

The event name being part of the key is what lets one click produce both a lead
and a later purchase.

## Testing it

Fire a postback by hand, substituting a real click id from your
[Clicks report](https://app.postbackx.com/clicks):

```bash
curl -i "https://postbacks.postbackx.com/postback?click_id=REAL_CLICK_ID&payout=18.00&event_name=lead&transaction_id=manual-test-1"
```

A `200` with a `conversion_id` means the whole chain works. Run it again and you
should get `duplicate: true` — proof that deduplication is doing its job.

If you get `400`, the click id was empty: check that your offer source's macro
matches the parameter you are sending it in. If you get `404`, the id does not
exist — a typo, or a click from a different organization.

For what to do when postbacks are not arriving at all, see
[Conversions are missing](/guides/missing-conversions).
