All docs pages

Billing

Stripe

Connect Stripe: what to pass at checkout, which webhook events, and where the signing secret is.

1. Pass the referral at checkout

// Browser: read the referral and send it to the endpoint that creates the Checkout Session.
const ref = window.referralmeter?.ref() ?? null;

// Server, in stripe.checkout.sessions.create({...}):
client_reference_id: ref ?? undefined,
metadata: { referralmeter_ref: ref ?? "" },
subscription_data: { metadata: { referralmeter_ref: ref ?? "" } }, // subscriptions only

// Payment Links, the pricing table and Buy Buttons need no code: the script adds client_reference_id itself.

Referralmeter reads referralmeter_ref from that field on the payment Stripe sends back. To mark a purchase as credits or a top-up (so your credits rule applies), also set kind: "credits" in the same metadata.

2. Connect the webhook

Billing connections → Stripe → paste a restricted key with only "Webhook Endpoints: Write" permission. Referralmeter creates the webhook endpoint in your Stripe account itself, so there is no signing secret to copy.

Create the key in Stripe → Developers → API keys → Create restricted key, with Webhook Endpoints: Write and nothing else. Referralmeter creates one endpoint for your program, pinned to API version 2025-02-24.acacia, and stores its signing secret encrypted. Prefer to make the endpoint yourself? Add it in Stripe → Developers → Webhooks with the URL from Billing connections and the events below, then paste its whsec_… signing secret instead.

Events Referralmeter uses:

  • checkout.session.completed
  • checkout.session.async_payment_succeeded
  • invoice.paid
  • refund.created
  • charge.dispute.created
  • customer.subscription.deleted

Test mode

Stripe marks test-mode events as test. They are recorded and shown, and never paid out. Connect a test-mode key to run the verification, then a live key for real traffic (or connect live and verify with a real purchase you refund).

Good to know

Subscriptions: put the referral on subscription_data.metadata too, so every renewal (invoice.paid) carries it. Metered prices count as usage; your program decides whether usage pays commission.