Docs navigation

Reference

Webhooks

Push delivery for the event feed: commission and program state changes land on your HTTPS endpoint as signed POSTs. Subscribe via the REST API, the subscribe_webhook MCP tool, or the dashboard.

Event types

TypeFires when
commission.createda new conversion appears on any connected network
commission.approveda pending commission is validated by the network
commission.reverseda commission is declined or clawed back
commission.paida commission is included in a payout
program.approveda program application is accepted
program.terminateda program relationship ends
sync.auth_errora network rejects your stored credentials (time to re-enter them)

Events are diff-based: the sync engine compares each run against stored state, so a re-run never produces duplicate events.

Delivery format

Each delivery is a JSON POST:

json
{
  "id": "5f0c7e0a-...",
  "type": "commission.approved",
  "created_at": "2026-07-09T02:14:00Z",
  "payload": { "transaction_id": "...", "network": "awin",
               "commission_amount": 12.4, "currency": "GBP",
               "attribution_tag": "yt-desc-2026-07" }
}
HeaderContents
X-AffiliateOS-SignatureHMAC of the raw body: sha256=<hex>
X-AffiliateOS-Eventthe event type
X-AffiliateOS-Deliveryunique delivery id (stable across retries of the same delivery)
Payloads never contain credentials or raw network responses, only the normalized fields. That’s a hard rule, not a formatting choice.

Verifying signatures

The secret (whsec_...) is returned once when you create the endpoint. Compute an HMAC-SHA256 of the raw request body and compare in constant time:

typescript
import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(rawBody: string, header: string, secret: string): boolean {
  const expected = 'sha256=' + createHmac('sha256', secret).update(rawBody).digest('hex');
  const a = Buffer.from(expected);
  const b = Buffer.from(header);
  return a.length === b.length && timingSafeEqual(a, b);
}

Verify against the raw body bytes, not a re-serialized object; JSON key order matters to the digest.

Retries and failure handling

BehaviorValue
Timeout per attempt15 seconds
Retry ladder after a failure1m, 5m, 30m, 2h, 12h, then the delivery is marked failed
Endpoint auto-disableafter 20 consecutive failed deliveries the endpoint is disabled until you re-enable it
Success criteriaany 2xx response; everything else counts as a failure

Respond 2xx quickly and process asynchronously. If your endpoint is flaky, deliveries queue and retry; if it stays down, check the dashboard’s developers page for delivery history.

Prefer polling?

The same events are available pull-style at GET /v1/events or the check_events MCP tool, using the returned high-water mark as the after parameter. Agents working in-session should poll; webhooks are for standing automation.