Receive real-time HTTP notifications when events happen in your affiliate program.
Configure a webhook URL and select which events you want to receive. When an event occurs, we POST a JSON payload to your URL with an HMAC-SHA256 signature for verification. Create and manage webhooks from the Event Webhooks section of your dashboard's Developer API page, or via the REST API: POST /api/v1/webhooks to create, PATCH /api/v1/webhooks/:id to update url, events, or the active flag, and GET /api/v1/webhooks/:id/deliveries to inspect recent delivery attempts.
| Event | Description |
|---|---|
| conversion.created | A new conversion was tracked (Stripe, Paddle, Lemon Squeezy, Gumroad, GoPay, Apple In-App Purchases, the tracking script, the dashboard, or the API) |
| conversion.updated | A conversion status changed (catch-all for any status transition) |
| conversion.approved | A conversion was approved by the merchant |
| conversion.rejected | A conversion was rejected by the merchant |
| conversion.paid | A conversion was paid out to the affiliate |
| affiliate.joined | An affiliate joined one of your campaigns (join status is included in the payload) |
| affiliate.approved | A pending affiliate was approved |
| affiliate.rejected | A pending affiliate was rejected |
| affiliate.payout_details_completed | An affiliate completed their payout details (PayPal/Wise email saved, or Stripe payouts enabled). Fires once per affiliate |
| payout.completed | An affiliate payout was successfully processed |
| payout.failed | An affiliate payout attempt failed |
{
"event": "conversion.created",
"data": {
"conversionId": "stripe_7PtIfIqd_123",
"campaignId": "PAbeJtXF39gDMUPYGZqZX",
"affiliateId": "lRCbRMSvBcGg4HszLCXLr",
"amount": "100.00",
"taxAmount": null,
"commission": "20.00",
"currency": "usd",
"status": "pending"
},
"timestamp": "2026-04-13T10:30:00Z",
"id": "wh_del_abc123"
}taxAmount is null unless the merchant calculates commission on the net sale (excluding tax). When set, amount is the net figure and the gross sale is amount + taxAmount.
Every webhook delivery includes an X-LinkJolt-Signature header in the form t=TIMESTAMP,v1=HEX. Verify it with an HMAC-SHA256 of `${timestamp}.${rawBody}` using your webhook secret, and reject anything older than 5 minutes for replay protection.
const crypto = require('crypto');
function verifyWebhook(rawBody, sigHeader, secret) {
const parts = Object.fromEntries(
sigHeader.split(',').map(p => p.split('='))
);
const { t: timestamp, v1: signature } = parts;
if (!timestamp || !signature) return false;
// Replay protection: reject if older than 5 minutes
const age = Math.floor(Date.now() / 1000) - parseInt(timestamp, 10);
if (Math.abs(age) > 300) return false;
const expected = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${rawBody}`)
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(expected, 'hex'),
Buffer.from(signature, 'hex')
);
}Each event is delivered once on a best-effort basis. If your endpoint returns a non-2xx response or times out, the failure is recorded but not automatically retried. Every attempt appears in the delivery log (dashboard, or GET /api/v1/webhooks/:id/deliveries), and failed deliveries can be resent from the dashboard log, so you can recover missed events without re-fetching from the REST API. After 5 consecutive failures the subscription is paused automatically and the account is notified by email and in-app. Re-enable it from the Event Webhooks section of your dashboard, or with PATCH /api/v1/webhooks/:id {"active": true}, which also resets the failure count.