Skip to content
 

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&currency=USD"
ParameterRequiredNotes
aon_click_idYesThe click id AON passed to your landing page (typically aci_…); send it back unchanged.
event_nameYesExact, case-sensitive Goal event declared on the Offer.
order_id, event_id, partner_txn_idOptional (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 + currencyRequired for CPS Goals; optional pair otherwiseDecimal 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:

  1. AON fetches eligible offers from your Offer Fetch endpoint.
  2. A user follows a tracked offer link.
  3. The click is resolved and attribution context is preserved.
  4. 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.

SegmentMeaningExample reasonsAction
2xxAccepted, already recorded, unmapped, reversed, or already reverseddata.result is accepted, already_recorded, unmapped, reversed, or already_reversedNo action needed
4xxTerminal request, security, identity, attribution, Goal, or reversal rejectionStable reason in data.reason; data.retryable: falseCorrect the request or integration before sending again
410Request used the retired JSON lane (AON-Protocol-Version header present)postback_json_lane_retired in extra.reasonSwitch to the GET query binding
500Pre-intake AON failureinternal_error; retryable: trueRetry with backoff and preserve the same business identity
503Intake unavailable or durable processing deferredpostback_intake_unavailable; retryable: trueRetry 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:

  1. the same Partner route (partner_id);
  2. the same aon_click_id the conversion carried;
  3. the same event_name (the same Goal); and
  4. the same business identity field and value the conversion carried. Identity fields never cross: a conversion reported with order_id=ord_10001 is not found by event_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_id plus event_name already 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 returns data.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 returns already_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&currency=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

HTTPdata.resultdata.reasonMeaning and action
200reversedREVERSEDThe conversion was reversed. Done.
200already_reversedALREADY_REVERSEDIt was already reversed; nothing changed. Done.
404rejectedREVERSAL_TARGET_NOT_FOUNDNo conversion matches. Check aon_click_id, event_name, and that you used the same identity field and value as the conversion.
409rejectedREVERSAL_TARGET_AMBIGUOUSMore than one conversion matches. Resend with the business identity used on the original conversion.
200disputedREVERSAL_DISPUTEDThe conversion was acknowledged or invoiced, so a dispute was opened. data.dispute_id identifies it; AON review decides.
200already_disputedREVERSAL_DISPUTE_EXISTSA dispute or review already exists; nothing changed.
409rejectedREVERSAL_ITEM_HELDThe item is held by AON review.
409rejectedREVERSAL_INVOICE_PAIDThe statement invoice carrying this conversion is fully paid.
409rejectedREVERSAL_ALREADY_ADJUDICATEDA dispute on this item was already decided: rejected (upheld, the charge stands) or adjusted.
422rejectedREVERSAL_DISPUTE_UNAVAILABLEAON could not open the dispute because of billing configuration. Contact support, then resend.
409rejectedREVERSAL_WINDOW_CLOSEDThe conversion's settlement is already settled or paid out and can no longer change.
400rejectedINVALID_REVERSAL_REASONreason is missing or not one of the six values above.
400rejectedinvalid_actionaction 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=confirm

AON 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.

HTTPdata.resultdata.reasonMeaning and action
200acknowledgedACKNOWLEDGEDRecorded. data.acknowledged_at and data.acknowledged_source are returned. Done.
200already_acknowledgedALREADY_ACKNOWLEDGEDAlready acknowledged; the first time and source are returned. Done.
404rejectedACK_TARGET_NOT_FOUNDNo conversion of this Partner matches.
409rejectedACK_TARGET_AMBIGUOUSMore than one conversion matches. Resend with the original business identity.
409rejectedACK_SETTLEMENT_NOT_CONFIRMEDThe settlement is not in a confirmable state (for example frozen or settled).
409rejectedACK_CONVERSION_REVERSEDThe conversion was already reversed.
409rejectedACK_ITEM_UNDER_REVIEWA dispute, review, or hold is open.
422rejectedACK_NOT_BILLABLEThe 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 code field 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.

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.