Endpoints
Order status
Report how an attributed order is progressing — confirmed, paid, delivered, cancelled, returned, refunded — and let the platform move the matching commission through its lifecycle for you. POST /api/v1/order-status is asynchronous: it accepts the event with 202 and applies commission effects in the background.
Each order-status update is matched to a conversion you previously reported (see Conversions) by its externalOrderId, optionally narrowed by clickId. The platform then advances the related commission according to the status you send. You never compute commission state yourself — you just keep us informed of the order, and the rules below do the rest.
X-Api-Key plus an HMAC-SHA256 X-Signature over `${X-Timestamp}.${rawRequestBody}`. See Authentication for the required headers and signing details.Request fields
The request body is a single JSON object with the following fields:
externalOrderId(required) — your order identifier, matching the order/conversion you reported earlier. This is how the event is bound to a commission.status(required) — one ofpending,confirmed,paid,delivered,cancelled,returned,refunded,commission_approved,commission_rejected. Any other value is rejected with400.clickId(optional) — narrows the match to a specific attributed click when an order could otherwise be ambiguous.statusUpdatedAt(optional, ISO 8601) — when the status actually changed in your system. Defaults to the time we receive the event. It also participates in deduplication (see below).reason(optional) — a short, human-readable explanation, useful for cancellations, returns and refunds.metadata(optional) — an arbitrary JSON object stored alongside the event for your own reference.
Status reference
Each status maps to a defined effect on the matching commission. This table is generated from the same reference the API enforces, so it is always accurate:
| Status | Meaning | Commission effect |
|---|---|---|
pending | Order placed, not yet confirmed. | Commission stays pending. |
confirmed | Order confirmed by the merchant. | Commission progresses toward hold/approved. |
paid | Payment captured. | Supports approval/payable progression. |
delivered | Order delivered to the buyer. | Starts the commission hold window before it becomes payable. |
cancelled | Order cancelled. | Commission rejected (clawback) unless already paid. |
returned | Order returned. | Commission rejected (clawback) unless already paid. |
refunded | Order refunded. | Commission rejected (clawback) unless already paid. |
commission_approved | Explicitly approve the commission. | Commission approved. |
commission_rejected | Explicitly reject the commission. | Commission rejected. |
Transition rules
The commission lifecycle is driven by the statuses you report. The important transitions are:
Delivered → hold → payable
A delivered status starts the commission hold window. The commission is held (not yet payable) for the configured hold period — this gives room for returns and disputes. Once the hold period elapses without a reversing event, the commission automatically becomes payable and is eligible for payout. You do not need to send anything to flip it to payable; the platform does it when the window closes.
Cancelled / returned / refunded → rejected
A cancelled, returned or refunded status rejects (claws back) the related commission — unless it has already been paid. A paid commission is terminal: a reversal event after payout is accepted by the API but does not change a paid commission. Correcting an already-paid commission requires a manual super-admin correction.
Paid is immutable
Once a commission reaches the paid state it is locked. Status events that would normally reverse or edit it are still accepted (202) but are skipped during async processing because the transition is not allowed. The same is true for any other disallowed transition: the API does not fail the request, but the processor records that it was skipped — review the outcome in your dashboard.
202 means “accepted for processing”, not “commission changed”. Disallowed transitions (e.g. editing a paid commission) are queued, then quietly skipped. Always confirm the final commission state in the dashboard rather than inferring it from the HTTP status.Safe retry
Order-status updates are idempotent. If a request times out or you are unsure whether it landed, re-send it with the same Idempotency-Key and the same body. The platform recognises the retry and returns the original outcome instead of applying the effect twice. Use a stable, deterministic key per logical event — for example order-status-<orderId>-<status>.
Duplicate status behavior
Independently of the idempotency key, the platform also deduplicates by content: a status event that repeats the same merchant + externalOrderId + status (and statusUpdatedAt, when supplied) as one already recorded is treated as a duplicate and has no additional effect. This means re-emitting the same transition from your system is always safe — you will never double-apply a commission effect by reporting the same status twice.
Endpoint
Update order status
Update the lifecycle status of an order so commissions settle correctly. Statuses: pending, confirmed, paid, delivered, cancelled, returned, refunded, commission_approved, commission_rejected.
{
"externalOrderId": "ORD-1001",
"status": "delivered",
"statusUpdatedAt": "2026-06-16T12:00:00Z"
}{
"eventId": "osevt_…",
"status": "RECEIVED",
"duplicate": false
}Signed example
A complete signed delivered update with cURL and OpenSSL. The signature is computed over `${timestamp}.${body}`, and the Idempotency-Key makes the call safe to retry:
# 1. Build the JSON body exactly as it will be sent on the wire.
BODY='{"externalOrderId":"ORD-10293","status":"delivered","statusUpdatedAt":"2026-06-14T09:30:00Z","reason":"Carrier confirmed delivery"}'
# 2. Timestamp (unix seconds) — must be within the allowed tolerance.
TS=$(date +%s)
# 3. Sign "${TS}.${BODY}" with your signing secret (lowercase hex).
SIG=$(printf '%s' "${TS}.${BODY}" | openssl dgst -sha256 -hmac "$AFF_SIGNING_SECRET" -r | cut -d' ' -f1)
curl -sS -X POST https://api.example.com/api/v1/order-status \
-H "Content-Type: application/json" \
-H "X-Api-Key: $AFF_API_KEY" \
-H "X-Timestamp: $TS" \
-H "X-Signature: $SIG" \
-H "Idempotency-Key: order-status-ORD-10293-delivered" \
-d "$BODY"
# -> 202 Accepted. The status event is queued; commission effects are applied
# asynchronously. Re-send the SAME request with the SAME Idempotency-Key to
# retry safely — duplicates are deduped, not double-counted.To receive these transitions back as outbound events — for example, to update your own ledger when a commission becomes payable or is rejected — subscribe via Webhooks.