Outbound Webhooks
Outbound webhooks let AffiliateBase notify your own systems when affiliate program activity happens.
Use them when you want to:
- create or update affiliate records in your CRM
- notify your team when an affiliate is approved
- sync referrals and conversions into a warehouse
- trigger internal commission review or payout workflows
- keep another system up to date without polling the REST API
Create a webhook endpoint
- Open AffiliateBase.
- Go to Settings -> Webhooks.
- Click Create endpoint.
- Enter a name, such as
Production CRM. - Enter an HTTPS endpoint URL from your app, automation tool, or integration platform.
- Select the event types you want to receive.
- Save the endpoint.
- Copy the signing secret immediately. It is only shown once.
Use a test or staging endpoint first. After your receiver validates signatures and returns successful responses, create the production endpoint.
Available events
AffiliateBase can send events for core affiliate program lifecycle changes:
| Event | When it fires |
|---|---|
affiliate.created | An affiliate record is created |
affiliate.approved | An affiliate moves into the active state |
referral.created | A referral is created from tracking activity |
referral.converted | A referral reaches conversion state |
commission.created | A commission is created from a sale |
commission.due | A commission moves into due state |
commission.voided | A commission is voided |
payout.paid | A payout is marked paid |
Your endpoint only receives events it is subscribed to.
Test delivery
After creating an endpoint:
- Open the endpoint from Settings -> Webhooks.
- Click Send test.
- Check your receiver logs.
- Confirm your endpoint returns a
2xxstatus code.
Test events use the first selected event type on the endpoint and include test: true in the payload.
Payload shape
Webhook requests are JSON.
{
"id": "webhook_event_id",
"type": "commission.created",
"occurred_at": "2026-05-29T14:21:12Z",
"data": {
"id": "commission_id",
"state": "pending",
"amount_cents": 1000,
"currency": "USD",
"affiliate_id": "affiliate_id",
"campaign_id": "campaign_id",
"sale_id": "sale_id",
"created_at": "2026-05-29T14:21:12Z"
}
}
Money amounts are in cents. Timestamps use ISO 8601.
Signed requests
AffiliateBase signs each webhook request with Svix-style headers:
svix-idsvix-timestampsvix-signature
Verify the signature before processing the event.
The signed content is:
svix-id.svix-timestamp.raw_request_body
The signature uses HMAC SHA-256 and your endpoint signing secret.
Example verification in Node.js
import crypto from "node:crypto";
function verifyAffiliateBaseWebhook({ rawBody, headers, signingSecret }) {
const messageId = headers["svix-id"];
const timestamp = headers["svix-timestamp"];
const signatureHeader = headers["svix-signature"] || "";
const expected = crypto
.createHmac("sha256", signingSecret)
.update(`${messageId}.${timestamp}.${rawBody}`)
.digest("base64");
const received = signatureHeader.replace(/^v1,/, "");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(received)
);
}
Use the raw request body exactly as received. Parsing and re-stringifying JSON before verification will change the signature input.
Delivery logs and retry
AffiliateBase stores delivery attempts for each endpoint.
Open an endpoint in Settings -> Webhooks to see:
- event type
- delivery state
- attempt count
- last HTTP status or error code
- recent delivery history
If a delivery fails, fix the receiver and click Retry.
Receiver requirements
Your endpoint should:
- accept
POSTrequests withContent-Type: application/json - verify the signature before doing work
- return a
2xxstatus code after the event is accepted - process events idempotently by webhook event
id - finish quickly and hand off slow work to a background job
AffiliateBase treats non-2xx responses as failed deliveries.
Security notes
- Use HTTPS for production endpoints.
- Store the signing secret in your server-side secrets manager.
- Do not expose the signing secret in client-side code.
- Reject requests with missing or invalid signatures.
- Keep a replay window for
svix-timestamp, such as five minutes. - Make your receiver idempotent so retries do not duplicate work.