All docs pages

Reference

Webhooks to your systems

Signed events Referralmeter sends you, on Pro and Growth.

Referralmeter can tell your own systems when something happens. Add an endpoint under Webhooks in the dashboard, on Pro or Growth. You can have 5. Your plan lapsing pauses delivery; it doesn't delete anything.

Events

EventWhen
affiliate.appliedSomeone applied through your portal
affiliate.approvedAn affiliate was approved
referral.createdAn affiliate's visitor signed up or bought for the first time
customer.convertedA referred customer made their first payment
commission.createdA payment earned a commission
commission.approvedA commission became payable
commission.reversedA refund or dispute clawed a commission back
payout.createdA payout batch was created
payout.paidA payout batch was marked paid
verification.passedAn install verification passed

Verification test traffic only ever sends verification.passed. Events carry livemode where it applies, so you can tell provider test mode apart.

The request

{
  "id": "9f1c2b9e-…",
  "type": "commission.created",
  "created_at": "2026-11-06T12:00:00.000Z",
  "data": {
    "commission_id": "…",
    "affiliate_id": "…",
    "affiliate_code": "maya",
    "referral_id": "…",
    "amount_cents": 1470,
    "currency": "usd",
    "status": "pending",
    "rate_label": "30% recurring",
    "livemode": true
  }
}

Affiliate events include the affiliate's name and email, and customer events the customer's email and your user id. Events never include payout details, tax forms or IP data. id is the same on every retry, so use it to ignore duplicates.

Check the signature

Every request has a Referralmeter-Signature header: t=<unix seconds>,v1=<hex>. v1 is an HMAC-SHA256 of <t>.<raw body> with your endpoint's signing secret, which is shown once, when you add it. Check it against the raw body, and refuse old timestamps so a captured request can't be replayed.

import { createHmac, timingSafeEqual } from "node:crypto";

function verified(rawBody, header, secret) {
  const { t, v1 } = Object.fromEntries(header.split(",").map((p) => p.split("=")));
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const want = createHmac("sha256", secret).update(t + "." + rawBody).digest();
  const got = Buffer.from(v1 ?? "", "hex");
  return got.length === want.length && timingSafeEqual(got, want);
}

Delivery

Answer with any 2xx within 5 seconds. A failed delivery is tried six times over about 40 hours, then marked failed; retries run hourly, so a retry can come later than its schedule. The dashboard lists recent deliveries with what your endpoint answered, for 30 days, and Send test posts a webhook.test event on demand.

Endpoints must be public https on the standard port. Requests are never sent to private addresses, checked again on each send, and redirects are not followed. The event body is deleted from our side once a delivery ends.