Generic webhook
Any system that can POST signed JSON: the contract for providers without their own adapter.
Any system that can POST signed JSON: the contract for providers without their own adapter.
Connect
Create the connection with {"provider": "generic", "programId": "prg_…"} and POST each user event to the webhook URL:
{ "type": "user.created", "customerRef": "usr_8f2k", "email": "dana@example.com", "name": "Dana", "createdAt": "2026-10-20T12:00:00Z", "emailVerified": true, "metadata": { "referalli_anon_id": "…" } }type is user.created (default), user.updated, user.deleted, user.banned or user.unbanned.
Sign it with x-referalli-signature: t=<unix seconds>,v1=<hex HMAC-SHA256 of "{t}.{raw body}"> using the connection secret; signatures more than 5 minutes off are refused. The original body-only x-webhook-signature (hex HMAC of the body) still works for existing integrations.
Every other connector's events can be expressed in this shape, so a provider we don't cover yet works today.
Referral context
On your sign-up page, with the tracking script loaded, window.aff.getReferral() returns the visitor's referral. Put it where this provider carries it (below), under the default keys referalli_anon_id, referalli_click_id and referalli_coupon. The older referally_* spellings are still read. Referalli never links users by email: without these keys a sign-up is not attributed.
For Generic webhook the referral is read from: metadata.*.
Check it
Each webhook delivery is answered with what Referalli did per user (attributed, partnerId, matchedVia, or the reason it wasn't); signed-protocol calls take "test": true on /signups to see the answer without storing anything. Every connector is held to the same conformance suite.