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

  1. Go to Settings > Webhooks in your PromoteKit dashboard
  2. Click Add Endpoint to create a new webhook endpoint
  3. Enter your endpoint URL (must be HTTPS)
  4. Select which event types you want to receive
  5. 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:

EventDescription
affiliate.createdA new affiliate is created (from the dashboard, API, or affiliate portal signup)
affiliate.approvedAn affiliate is approved (individually or via bulk approval)
referral.createdA new referral is tracked (from Stripe, the dashboard, API, or tracking script)
referral.convertedA referral receives their first commission (first paid conversion)
commission.createdA 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:

HeaderDescription
svix-idUnique message identifier
svix-timestampUnix timestamp of when the message was created
svix-signatureThe signature(s) for the payload

Finding Your Signing Secret

  1. Go to Settings > Webhooks in your dashboard
  2. Click on your endpoint
  3. Click Signing Secret to reveal your endpoint's secret

The secret starts with whsec_.

Install the Svix library for your language:

npm install svix

Then 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-id header to deduplicate.
  • Verify signatures: Always verify the webhook signature before processing events.
  • Use HTTPS: Webhook endpoints must use HTTPS.