Back to blog

How to track affiliate sales with Stripe webhooks

Stripe webhooks are the backbone of any reliable affiliate tracking system. They let you attribute sales, handle subscriptions, process refunds, and cancel pending commissions — all automatically. Here is how to set them up.

T
Traaaction Team

Why webhooks matter for affiliate tracking

Affiliate tracking relies on a simple chain: a visitor clicks a tracked link, a cookie is stored, the visitor makes a purchase, and the affiliate earns a commission. The tricky part is the last step. You need a reliable way to know that a payment actually went through, and Stripe webhooks are the only production-grade answer.

Unlike redirect-based tracking or client-side pixel fires, webhooks are server-to-server. They cannot be blocked by ad blockers, they survive browser crashes, and they work for recurring payments that happen while the customer is offline. If you sell anything through Stripe and run an affiliate program, webhooks are non-negotiable.

The 4 webhooks you need

A complete affiliate tracking setup requires exactly four Stripe webhook events. Each one covers a different stage of the payment lifecycle.

1. checkout.session.completed

This event fires when a customer completes a Stripe Checkout session. It is where initial attribution happens. For one-time purchases, you create a sale commission. For subscriptions, you create a first-month recurring commission.

The key is passing the affiliate click ID in the session metadata so you can attribute the sale back to the right affiliate. You should set it in two places for redundancy: the metadata object and the client_reference_id field.

const session = await stripe.checkout.sessions.create({
  metadata: { tracClickId: clickId },
  client_reference_id: clickId,
  mode: 'subscription', // or 'payment'
  // ... line items, success_url, etc.
})

2. invoice.paid

For SaaS businesses with subscriptions, the real value of affiliate tracking is in recurring commissions. The invoice.paid event fires every time a subscription renewal is charged successfully — month 2, month 3, and so on.

Your webhook handler should look up the subscription ID, verify that month 1 was already tracked (to avoid processing unrelated invoices), and check whether the affiliate has hit their recurring commission limit. Month counting should be database-based, not parsed from invoice numbers, to avoid edge cases with prorations and credits.

3. charge.refunded

Refunds are the most important event for program integrity. When a charge is refunded, you need to claw back the affiliate commission. If the commission is still pending or in its hold period, you simply delete it. If it has already been paid out, you delete it and apply a negative balance to the affiliate account — the amount is deducted from their next payout.

A robust implementation uses a dual lookup strategy: first try to find the commission via the original checkout session, then fall back to looking up the charge invoice for subscription renewals.

4. customer.subscription.deleted

When a customer cancels their subscription, any pending commissions for future months should be removed. Commissions that have already matured (moved past the hold period) or been paid out are preserved — they were earned for months the customer did pay for.

After deleting pending commissions, always recalculate the affiliate balance to keep the ledger accurate.

The full attribution flow

Putting it all together, the attribution chain looks like this:

  1. Affiliate shares a tracked link
  2. Visitor clicks the link; a click ID is generated and stored in a first-party cookie (90 days)
  3. Visitor browses the site and decides to purchase
  4. Your checkout page reads the cookie and passes the click ID to Stripe
  5. Stripe fires checkout.session.completed; your webhook attributes the sale to the affiliate
  6. A commission is created with a hold period (typically 30 days for sales, 3 days for leads)
  7. After the hold period, the commission matures and becomes available for payout

For subscriptions, steps 5 through 7 repeat on each renewal via the invoice.paid event. The original attribution is stored once and reused — no cookie needed after the first purchase.

Hold periods protect everyone

A commission should not be payable immediately. Hold periods give you time to catch chargebacks, refund requests, and fraudulent sign-ups before money leaves your account. Industry standards range from 3 to 30 days depending on the commission type. Lead commissions can have shorter holds because the chargeback window does not apply. Sale and recurring commissions typically need 30 days to account for Stripe dispute timelines.

Automate with Traaaction

Setting up webhook handlers, attribution logic, commission calculation, hold periods, clawbacks, and balance management is a significant engineering effort. Traaaction handles all of this out of the box. You configure your four webhook events in Stripe, add the click ID to your checkout metadata, and the platform takes care of the rest — including recurring commission tracking, refund clawbacks, and payouts via Stripe Connect, IBAN, or PayPal.

The setup takes about five minutes. Traaaction uses a subscription model with a free tier (no per-sale fees), so you can start tracking without any upfront cost.

Try Traaaction free

Automate Stripe affiliate tracking in 5 minutes. No per-sale fees.

Get started

Explore more: Recurring commissions · Commission structures · SaaS · Glossary · Blog

How to Track Affiliate Sales with Stripe Webhooks | Traaaction Blog | Traaaction