Postbacks & attribution
Partner docs are supply-side: they help offer providers understand what happens after AON serves an eligible offer. Use this page to align tracking click, conversion, and postback responsibilities.
Reach this step after the approved Partner has completed the Offer Fetch URL, credentials, and signed fetch test. The completion check below applies to the Provider path that reports conversions to AON; it does not require a Developer or Agent receiver webhook.
Endpoint reference lives in API docs
This page is an onboarding task guide. For endpoint-level request and response details, use API Tracking.
Current v1.0 source
The single current contract is the Postback specification. Its authoritative query parameter table defines every Provider-to-AON field. This page covers only the Provider-to-AON onboarding path; do not copy it as a second field specification.
Provider quickstart: report a conversion to AON
Prerequisites: your Partner route is enabled, its source IP is allowlisted, and
you have the aon_click_id AON passed to your landing page for the converting
click (see Tracking Macros).
Partner postbacks use one binding: an HTTP GET with every parameter in the
query string. There is no request body, no protocol-version header, and no
AppKey/AppSecret signature header. The URL template matches the S2S Postback
card in Partner Portal:
GET https://api.example.test/v1/postback/{partner_id}?aon_click_id={CLICK_ID}&event_name={EVENT_NAME}Replace {CLICK_ID} with the aon_click_id value you captured, unchanged, and
{EVENT_NAME} with the Offer Goal you are reporting. Optionally add one stable
business identity (order_id, event_id, or partner_txn_id) and, for a
revenue-share Goal, the amount and currency pair:
curl "https://api.example.test/v1/postback/019f5f65-dbc1-7c3c-9ef9-9d6d2d8ae001?aon_click_id=aci_0192f3a4b5c67d8e9f0a1b2c3d4e5f60&event_name=purchase&order_id=ord_10001&amount=179.99¤cy=USD"| Parameter | Required | Notes |
|---|---|---|
aon_click_id | Yes | The click id AON passed to your landing page (typically aci_…); send it back unchanged. |
event_name | Yes | Exact, case-sensitive Goal event declared on the Offer. |
order_id, event_id, partner_txn_id | Optional (required for Goals that count every conversion) | Stable business identity. Each is a separate namespace: order_id=x and event_id=x are different identities. |
amount + currency | Required for CPS Goals; optional pair otherwise | Decimal string and ISO 4217 code, always sent together. |
The expected first success is HTTP 200 with data.result set to accepted
and a data.correlation_id you can quote to support.
Current 4xx responses are terminal: correct the URL, parameters, attribution,
or Goal mapping instead of retrying the same request.
Both 500 and 503 are retryable AON-side failures.
Retry them with backoff while preserving the same stable business identity
(event_id, order_id, or partner_txn_id) across every attempt.
The JSON POST lane is retired
Requests that carry an AON-Protocol-Version header, with any value, are
rejected with HTTP 410 and reason postback_json_lane_retired. Move the
same fields into the GET query string shown above.
Developer callback handoff
Receiving an Agent or Developer conversion callback is not part of this Partner onboarding path. Use Developer Webhooks for the current receiver contract, required headers, raw-body verification, idempotency, retry schedule, and failure handling.
Attribution flow
The high-level flow is:
- AON fetches eligible offers from your Offer Fetch endpoint.
- A user follows a tracked offer link.
- The click is resolved and attribution context is preserved.
- A conversion or partner postback reconciles the outcome.
The Partner page explains where your systems fit in that flow. The API Reference remains the source for endpoint-specific request and response details.
What partners own
Partners usually own:
- Landing page redirect integrity after a tracked click.
- Conversion event quality and dedupe logic in their own systems.
- Sending a reversal when a reported order is refunded, charged back, or cancelled, and optionally a confirm when an order is known to be valid.
- Retry handling and observability for server-to-server callbacks.
- Reconciliation logs that preserve request or tracking identifiers.
Keep logs tied to your Offer Fetch request_id and downstream attribution
records so support teams can connect offer serving, clicks, and conversions.
When to use API Tracking docs
Use API Tracking when you need endpoint-level details for click redirects, conversion events, or partner postback callbacks. Do not copy those fields into Partner onboarding notes; link to the API Reference so the contract stays in one place.
Test and reconciliation checklist
- Confirm test traffic cannot trigger real billing, fulfillment, or inventory side effects.
- Keep retry behavior idempotent for conversion and postback handling.
- Log enough context to reconcile click, conversion, and Partner account state.
- Review operational settings in Partner Portal Setup.
Partner document-path completion
The Partner document path ends here when the Provider click/postback test has
evidence, conversion handling is idempotent, and reconciliation can connect
Offer Fetch, clicks, and conversion records. This is document-path completion,
not a live approval: this docs-path step is not live. ready_for_review only
means the integration can be submitted for review. Call the Partner live only
after it is approved and its production health is healthy. A Developer or Agent
receiver webhook is not a Partner readiness requirement.
Current response and failure semantics
GET /v1/postback/{partner_id} uses the HTTP status code as the primary
success/failure signal. Alert and retry logic should key off the status code
first; treat the response body as supporting detail, not the thing you branch
on.
| Segment | Meaning | Example reasons | Action |
|---|---|---|---|
| 2xx | Accepted, already recorded, unmapped, reversed, or already reversed | data.result is accepted, already_recorded, unmapped, reversed, or already_reversed | No action needed |
| 4xx | Terminal request, security, identity, attribution, Goal, or reversal rejection | Stable reason in data.reason; data.retryable: false | Correct the request or integration before sending again |
| 410 | Request used the retired JSON lane (AON-Protocol-Version header present) | postback_json_lane_retired in extra.reason | Switch to the GET query binding |
| 500 | Pre-intake AON failure | internal_error; retryable: true | Retry with backoff and preserve the same business identity |
| 503 | Intake unavailable or durable processing deferred | postback_intake_unavailable; retryable: true | Retry with backoff |
Every response uses the hosted envelope {code, message, data, extra}. On the
GET binding, data carries result, event_logged, reason,
correlation_id, and retryable for both successes and rejections; a failure
also sets code and message from the reason. The retired-lane 410 keeps
data as {} and reports the same diagnostics in extra.
Rejection body example
A reversal that matches no conversion:
{
"code": "REVERSAL_TARGET_NOT_FOUND",
"message": "REVERSAL_TARGET_NOT_FOUND",
"data": {
"result": "rejected",
"event_logged": true,
"reason": "REVERSAL_TARGET_NOT_FOUND",
"correlation_id": "<journal_id>",
"retryable": false
},
"extra": {}
}Reversals
When an order is refunded, charged back, or cancelled after you reported it,
reverse the Goal conversion by calling the same URL with two extra parameters:
action=reversal and a reason.
GET https://api.example.test/v1/postback/{partner_id}?aon_click_id={CLICK_ID}&event_name={EVENT_NAME}&action=reversal&reason={REASON}{REASON} is one of refunded, chargeback, merchant_cancelled,
invalid_order, fraud, or duplicate. Any other action value is rejected
with 400 invalid_action.
How AON finds the conversion
AON reverses exactly one previously accepted conversion that matches all of:
- the same Partner route (
partner_id); - the same
aon_click_idthe conversion carried; - the same
event_name(the same Goal); and - the same business identity field and value the conversion carried.
Identity fields never cross: a conversion reported with
order_id=ord_10001is not found byevent_id=ord_10001.
The business identity rule follows the Goal's dedup strategy:
- Goals that count the first conversion only (
dedup_strategy=first): identity is optional.aon_click_idplusevent_namealready identifies the single conversion. If you send an identity, it must match the original. - Goals that count every conversion (
dedup_strategy=all): identity is required, because one click can carry several conversions for that Goal.
A reversal always reverses the whole conversion; do not send amount or
currency. Partial reversals are not supported. Reversals use the same
Partner route and IP allowlist as conversions.
What a reversal does at each stage
Reversal is never refused just because a statement was confirmed. AON checks how far the conversion has progressed:
- Not acknowledged and not invoiced: the reversal succeeds and the
conversion's payout is removed from the statement (
REVERSED). - Acknowledged or invoiced: AON opens a dispute for you instead
(
200,data.result = "disputed",REVERSAL_DISPUTED) and returnsdata.dispute_id. AON review decides it; invoice amounts do not change until then. An accepted dispute (item refunded or adjusted) is offset by a credit note on the next statement; a rejected one (upheld) leaves the charge standing. Sending the reversal again returnsalready_disputed. - Not reversible: the item is held by AON (
REVERSAL_ITEM_HELD), the statement invoice is fully paid (REVERSAL_INVOICE_PAID), a dispute on the item was already decided, invoiced or not: rejected (upheld) or adjusted (REVERSAL_ALREADY_ADJUDICATED), or the settlement is settled or paid out (REVERSAL_WINDOW_CLOSED).
Example: convert, reverse, replay
This example uses a source configured for manual confirmation, before any individual acknowledgement or invoice. New conversions are automatically acknowledged by default when eligible; a reversal after that acknowledgement opens the dispute described above instead.
# 1. Report the conversion → 200, data.result = "accepted"
curl "https://api.example.test/v1/postback/019f5f65-dbc1-7c3c-9ef9-9d6d2d8ae001?aon_click_id=aci_0192f3a4b5c67d8e9f0a1b2c3d4e5f60&event_name=purchase&order_id=ord_10001&amount=179.99¤cy=USD"
# 2. Reverse it after a refund → 200, data.result = "reversed", data.reason = "REVERSED"
curl "https://api.example.test/v1/postback/019f5f65-dbc1-7c3c-9ef9-9d6d2d8ae001?aon_click_id=aci_0192f3a4b5c67d8e9f0a1b2c3d4e5f60&event_name=purchase&order_id=ord_10001&action=reversal&reason=refunded"
# 3. Send the same reversal again → 200, data.result = "already_reversed", data.reason = "ALREADY_REVERSED"
curl "https://api.example.test/v1/postback/019f5f65-dbc1-7c3c-9ef9-9d6d2d8ae001?aon_click_id=aci_0192f3a4b5c67d8e9f0a1b2c3d4e5f60&event_name=purchase&order_id=ord_10001&action=reversal&reason=refunded"A successful reversal response:
{
"code": "SUCCESS",
"message": "",
"data": {
"result": "reversed",
"event_logged": true,
"reason": "REVERSED",
"correlation_id": "<journal_id>",
"retryable": false
},
"extra": {}
}Each conversion can be reversed once. A repeated reversal has no further effect,
whatever reason it carries; treat both reversed and already_reversed as
final.
Reversal responses
| HTTP | data.result | data.reason | Meaning and action |
|---|---|---|---|
| 200 | reversed | REVERSED | The conversion was reversed. Done. |
| 200 | already_reversed | ALREADY_REVERSED | It was already reversed; nothing changed. Done. |
| 404 | rejected | REVERSAL_TARGET_NOT_FOUND | No conversion matches. Check aon_click_id, event_name, and that you used the same identity field and value as the conversion. |
| 409 | rejected | REVERSAL_TARGET_AMBIGUOUS | More than one conversion matches. Resend with the business identity used on the original conversion. |
| 200 | disputed | REVERSAL_DISPUTED | The conversion was acknowledged or invoiced, so a dispute was opened. data.dispute_id identifies it; AON review decides. |
| 200 | already_disputed | REVERSAL_DISPUTE_EXISTS | A dispute or review already exists; nothing changed. |
| 409 | rejected | REVERSAL_ITEM_HELD | The item is held by AON review. |
| 409 | rejected | REVERSAL_INVOICE_PAID | The statement invoice carrying this conversion is fully paid. |
| 409 | rejected | REVERSAL_ALREADY_ADJUDICATED | A dispute on this item was already decided: rejected (upheld, the charge stands) or adjusted. |
| 422 | rejected | REVERSAL_DISPUTE_UNAVAILABLE | AON could not open the dispute because of billing configuration. Contact support, then resend. |
| 409 | rejected | REVERSAL_WINDOW_CLOSED | The conversion's settlement is already settled or paid out and can no longer change. |
| 400 | rejected | INVALID_REVERSAL_REASON | reason is missing or not one of the six values above. |
| 400 | rejected | invalid_action | action is not conversion, reversal, or confirm. |
Confirm
New eligible conversions are acknowledged automatically by default. AON Admin
can configure a listing_source for manual confirmation; those conversions
continue to use the individual or monthly statement flow below. Changing the
policy affects only new conversions. Automatic acknowledgement does not issue
an invoice, record payment, or make the earning immediately withdrawable.
To tell AON a reported conversion is valid before the monthly statement, call
the same URL with action=confirm. Do not send reason, amount, or
currency; AON ignores them.
GET https://api.example.test/v1/postback/{partner_id}?aon_click_id={CLICK_ID}&event_name={EVENT_NAME}&action=confirmAON locates the conversion exactly as it does for a reversal. The Developer
earning becomes confirmed immediately. Confirming your monthly statement
acknowledges every remaining conversion on it, so action=confirm is optional.
| HTTP | data.result | data.reason | Meaning and action |
|---|---|---|---|
| 200 | acknowledged | ACKNOWLEDGED | Recorded. data.acknowledged_at and data.acknowledged_source are returned. Done. |
| 200 | already_acknowledged | ALREADY_ACKNOWLEDGED | Already acknowledged; the first time and source are returned. Done. |
| 404 | rejected | ACK_TARGET_NOT_FOUND | No conversion of this Partner matches. |
| 409 | rejected | ACK_TARGET_AMBIGUOUS | More than one conversion matches. Resend with the original business identity. |
| 409 | rejected | ACK_SETTLEMENT_NOT_CONFIRMED | The settlement is not in a confirmable state (for example frozen or settled). |
| 409 | rejected | ACK_CONVERSION_REVERSED | The conversion was already reversed. |
| 409 | rejected | ACK_ITEM_UNDER_REVIEW | A dispute, review, or hold is open. |
| 422 | rejected | ACK_NOT_BILLABLE | The conversion cannot yet enter a billable item. |
Reversal and confirm rejections are terminal (retryable: false); do not resend them
unchanged. Reversal outcomes report event_logged: true because every reversal
attempt is journaled and appears in Partner Portal Postback Logs; only
invalid_action is rejected before processing and reports
event_logged: false. A conversion
that was recorded only as unmapped has no payout and cannot be reversed.
Integration recommendations
- Alert on any non-2xx response — a response is not the same thing as a recorded conversion or reversal.
- Treat 500 and 503 as retryable: 503 means AON is temporarily unavailable (retry with backoff), and 500 means an AON-side failure where retries are safe because they are idempotent when the business identity is unchanged.
- Do not resend a 4xx-rejected request unmodified — inspect the reason and fix the parameters or event mapping before sending again.
- Validate the response body
codefield explicitly; do not infer success from response shape alone.
Inbound security boundary
GET /v1/postback/{partner_id} uses the configured Partner route, enablement,
and IP allowlist for both conversions and reversals. Do not add AppKey/AppSecret
HMAC, timestamp, nonce, or signature headers to the callback. AppKey/AppSecret
are reserved for AON's outbound Offer Fetch requests; see
Credentials & signing.
Historical HMAC configuration does not add an inbound signature requirement to postbacks.
Related pages
If your landing URL template needs AON to insert a tracking value, review Tracking Macros. Otherwise, there is no additional Partner onboarding step after Postbacks & Attribution.