Webhooks Overview
Receive real-time event notifications from PromoteKit
Webhooks
PromoteKit sends webhook events to notify your application in real-time when things happen in your affiliate program. You can use webhooks to trigger automations, sync data to external systems, or build custom workflows.
Setting Up Webhooks
- Go to Settings > Webhooks in your PromoteKit dashboard
- Click Add Endpoint to create a new webhook endpoint
- Enter your endpoint URL (must be HTTPS)
- Select which event types you want to receive
- Save the endpoint
You can manage your endpoints, view delivery logs, and retry failed deliveries from the Webhooks settings page.
Event Types
PromoteKit sends the following webhook events:
| Event | Description |
|---|---|
affiliate.created | A new affiliate is created (from the dashboard, API, or affiliate portal signup) |
affiliate.approved | An affiliate is approved (individually or via bulk approval) |
referral.created | A new referral is tracked (from Stripe, the dashboard, API, or tracking script) |
referral.converted | A referral receives their first commission (first paid conversion) |
commission.created | A new commission is generated (from Stripe payments, the dashboard, or API) |
Payload Format
All webhook events are sent as HTTP POST requests with a JSON body. The payload has the following structure:
{
"type": "affiliate.created",
"data": {
// The resource object in the same format as the API
}
}The data field contains the resource object in the same format as the corresponding API endpoint. For example, an affiliate.created event contains the same affiliate object you would get from the GET /affiliates/:id API endpoint.
affiliate.created / affiliate.approved
{
"type": "affiliate.created",
"data": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "affiliate@example.com",
"first_name": "Jane",
"last_name": "Doe",
"payout_email": "jane@example.com",
"links": [
{
"url": "https://yoursite.com?via=jane",
"code": "jane"
}
],
"promo_codes": [
{
"code": "JANE20",
"external_id": "promo_abc123"
}
],
"clicks": 0,
"approved": true,
"banned": false,
"details": null,
"new_paid_referral_notifications": true,
"created_at": "2025-01-15T10:30:00Z",
"campaign": {
"id": "660e8400-e29b-41d4-a716-446655440001",
"name": "Default Campaign",
"commission_type": "percentage",
"commission_amount": 20
}
}
}referral.created / referral.converted
{
"type": "referral.created",
"data": {
"id": "770e8400-e29b-41d4-a716-446655440002",
"email": "customer@example.com",
"subscription_status": "signed_up",
"signup_date": "2025-01-20T14:00:00Z",
"stripe_customer_id": "cus_abc123",
"created_at": "2025-01-20T14:00:00Z",
"affiliate": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "affiliate@example.com",
"first_name": "Jane",
"last_name": "Doe"
}
}
}commission.created
{
"type": "commission.created",
"data": {
"id": "880e8400-e29b-41d4-a716-446655440003",
"revenue_amount": 99.0,
"currency": "USD",
"commission_amount": 19.8,
"payout_status": "not_paid",
"referral_date": "2025-01-20T14:00:00Z",
"created_at": "2025-01-20T14:00:00Z",
"stripe_payment_id": "pi_abc123",
"affiliate": {
"id": "550e8400-e29b-41d4-a716-446655440000",
"email": "affiliate@example.com",
"first_name": "Jane",
"last_name": "Doe"
},
"referral": {
"id": "770e8400-e29b-41d4-a716-446655440002",
"email": "customer@example.com",
"subscription_status": "active",
"signup_date": "2025-01-20T14:00:00Z",
"stripe_customer_id": "cus_abc123",
"created_at": "2025-01-20T14:00:00Z"
},
"payout": null
}
}Verifying Webhook Signatures
PromoteKit signs all webhook payloads so you can verify they are authentic. Each webhook request includes the following headers:
| Header | Description |
|---|---|
svix-id | Unique message identifier |
svix-timestamp | Unix timestamp of when the message was created |
svix-signature | The signature(s) for the payload |
Finding Your Signing Secret
- Go to Settings > Webhooks in your dashboard
- Click on your endpoint
- Click Signing Secret to reveal your endpoint's secret
The secret starts with whsec_.
Verifying with the Svix Library (Recommended)
Install the Svix library for your language:
npm install svixThen verify the webhook:
import { Webhook } from "svix";
const secret = "whsec_your_secret_here";
const wh = new Webhook(secret);
// In your webhook handler:
app.post("/webhook", (req, res) => {
const headers = req.headers;
const payload = req.body; // Must be the raw request body string
try {
const event = wh.verify(payload, headers);
// Process the verified event
console.log("Event type:", event.type);
console.log("Event data:", event.data);
} catch (err) {
console.error("Webhook verification failed:", err);
return res.status(400).send("Invalid signature");
}
res.status(200).send("OK");
});You must use the raw request body when verifying webhooks. If your framework automatically parses JSON, you need to capture the raw body before parsing.
Manual Verification
If you prefer to verify manually, the signature is computed as an HMAC-SHA256 of the message ID, timestamp, and body:
signed_content = "${svix_id}.${svix_timestamp}.${body}"
signature = base64(hmac_sha256(base64_decode(secret), signed_content))Compare your computed signature against the one in the svix-signature header (after the v1, prefix).
Retry Behavior
If your endpoint returns a non-2xx status code, PromoteKit will retry the delivery with exponential backoff. You can view delivery attempts and manually retry failed deliveries from the Settings > Webhooks page in your dashboard.
Best Practices
- Respond quickly: Return a 2xx status code within 15 seconds. Process the event asynchronously if needed.
- Handle duplicates: Webhook deliveries may be retried. Use the
svix-idheader to deduplicate. - Verify signatures: Always verify the webhook signature before processing events.
- Use HTTPS: Webhook endpoints must use HTTPS.