affilink

Postback API reference

The server-to-server endpoint a merchant calls to report conversions. Base URL: https://api.affilink.co.il. For the step-by-step site setup, start with the integration guide.

Authentication & signing

Every request is signed HMAC-SHA256 with the offer's webhook_secret. A leaked click_id alone can never fabricate a conversion.

signature_base = "{timestamp}.{raw_json_body}"
signature      = hex( HMAC_SHA256(webhook_secret, signature_base) )

Required headers:

X-Affilink-Timestamp: 1735689600        (unix seconds)
X-Affilink-Signature: <hex>
Content-Type: application/json

Requests are rejected with 401 if the timestamp is more than 300 seconds from server time (replay protection) or the signature doesn't match.

POST /v1/postback

{
  "offer_id":          "off_8a2f...",
  "click_id":          "8f14e45f-ceea-4ab9-8c1e-1b3a2f9d0e11",
  "external_order_id": "ORDER-10293",
  "event_type":        "conversion",
  "amount":            149.90,
  "currency":          "ILS",
  "occurred_at":       "2026-07-12T10:15:00Z"
}
FieldRequiredNotes
offer_idyesMust belong to the org owning the signing secret.
click_idyes, unless is_renewalMust exist and be inside the offer's attribution window.
external_order_idyesYour own order/charge id - the idempotency key, unique per org per charge.
event_typeyesconversion | refund (refund reverses a prior conversion by external_order_id).
amountyesDecimal, major units. The sale amount - never the commission; commissions are computed server-side.
currencyyesISO 4217.
occurred_atnoDefaults to receipt time.
subscription_idrecurring offers onlyYour subscription/customer id - same value on the first charge and every renewal.
is_renewalno (default false)true for a renewal charge: omit click_id; identity is inherited from the first charge sharing subscription_id.
stagestaged offers onlylead | qualified | closed_won | closed_lost - see below.

Success response (200)

{
  "conversion_id":        "cv_1a2b...",
  "status":               "approved",
  "affiliate_commission": 14.99,
  "platform_fee":         1.50
}

Error codes

CodeMeaning
401Bad/missing signature or stale timestamp.
404click_id not found (or, for a refund, no conversion with that external_order_id).
409external_order_id already processed - idempotent no-op returning the original conversion_id. Instant offers only; staged offers update instead.
410Click found, but outside the offer's attribution window.
422Malformed payload (missing field, renewal without a first charge, etc.).
429Rate limited. Honor Retry-After-style backoff and retry.

Every request - valid or not - is written to an audit log before the response returns, so "we sent it, you never recorded it" disputes are always debuggable.

Refunds

"event_type": "refund" with the original external_order_id marks the conversion reversed and claws back the already-credited commission (immediate-clawback policy - the recovered amount nets against the affiliate's next payout).

Recurring subscriptions

For offers with recurring commissions: the first charge is a normal postback plus subscription_id. Renewals send is_renewal: true with the same subscription_id and no click_id - attribution is inherited from the first charge, with no attribution-window re-check. If the offer caps commissionable months, charges past the cap are tracked but earn nothing.

Staged conversions (CRM / lead-gen offers)

A B2B deal doesn't close at a checkout. Offers configured as staged send multiple postbacks with the same external_order_id, advancing a stage field: leadqualifiedclosed_won (or closed_lost). Commission is computed only at closed_won, using the amount sent at that point; earlier stages are tracking-only (send "amount": 0). Repeat external_order_ids are updates here, not 409s. Any CRM that can fire a webhook or a Zapier/Make automation on a deal-stage change can drive this - the API doesn't care what's on the other end.

GET fallback (legacy platforms)

For merchant stacks that can only fire a GET. Same validation and idempotency rules; weaker transport (no timestamp/replay window) - use only when POST isn't feasible:

GET https://api.affilink.co.il/v1/postback-get
  ?offer_id=off_8a2f
  &click_id=8f14e45f-...
  &external_order_id=ORDER-10293
  &amount=149.90
  ¤cy=ILS
  &sig={hex HMAC-SHA256 of "offer_id|click_id|external_order_id|amount|currency"}

Commission calculation (for reference)

The merchant only ever sends the sale amount. affilink resolves the rate (a negotiated per-affiliate override wins over the offer default), and computes the commission server-side. Platform fees and marketplace listing fees are charged to the organization on top - they never reduce the affiliate's commission.