How do you attribute Stripe Checkout payments to an affiliate?
Short answer: Save the verified affiliate referral against your own signup or checkout attempt, associate that record with a Stripe Checkout Session, and award commission only after your server confirms an eligible paid event. Keep an immutable referral decision and a separate commission ledger. A successful redirect is not proof of payment, and a campaign UTM tag is not a commission instruction.
Stripe Checkout Sessions expose a client_reference_id and metadata fields that can help reconcile a session with your internal record. Stripe also documents separate metadata paths for subscriptions and PaymentIntents. These fields do not automatically establish affiliate eligibility; your application must decide that under its program policy. See Stripe's Checkout Session reference and metadata guidance.
Design the attribution data model before writing code
Start with a referral record created when a visitor follows a valid partner link. Use a server-generated opaque identifier rather than trusting a partner ID submitted in an unverified browser form. Bind the referral to the application user or signup attempt when the user registers, subject to your published cookie window and consent rules. Preserve the original referring partner, campaign, attribution timestamp, source evidence and any manual override.
| Record | Suggested keys | Why it exists |
|---|---|---|
| Referral touch | referral_id, partner_id, captured_at | Evidence for the original attribution decision |
| Signup | user_id, referral_id | Links anonymous traffic to a known customer |
| Checkout attempt | checkout_attempt_id, session_id | Handles abandoned and repeated sessions |
| Billing identity | stripe_customer_id, subscription_id | Connects later invoices and renewals |
| Commission ledger | invoice_id, partner_id, state, amount | Prevents duplicate awards and supports refunds |
Keep personal data out of URL parameters and Stripe metadata. Use opaque IDs that resolve to your secured server records. This also makes it possible to change commission policies without rewriting historical billing events.
Create Checkout Sessions with stable references
When the user chooses a plan, create the Checkout Session on your server. Set client_reference_id to an internal checkout or signup key and place only non-sensitive reconciliation identifiers in the Session metadata. For a subscription flow, explicitly populate subscription_data.metadata when the subscription must retain a reference for future invoices. Stripe explains that metadata is not universally copied between related objects, so verify the exact object receiving each value instead of assuming inheritance.
Save the newly returned Session ID against the checkout attempt. If the visitor restarts checkout, create a new attempt linked to the same eligible signup; do not overwrite the original attribution record. If two affiliates claim the same signup, apply your published first-touch, last-eligible-touch or manually approved rule before opening Checkout. For background, compare the site's Stripe Payment Links tracking guide, which addresses a different purchase flow.
Verify paid events and handle asynchronous payment
Process Stripe webhooks server-side, verify the webhook signature and store each event ID for idempotency. A checkout.session.completed event can identify the Session and its customer or subscription. However, payment status and payment-method behavior matter. Do not pay solely because the browser reached a success URL. Confirm the relevant payment or invoice actually succeeded before creating an approved commission.
For recurring subscriptions, link later paid invoices to the Stripe subscription and your stable internal referral decision. Use a unique ledger key such as the invoice ID plus commission rule version. On refunds, disputes, credits or plan changes, append an adjustment instead of silently editing a historical award. Stripe's Checkout fulfillment documentation explains why webhook-based fulfillment is important.
Worked example: trial signup and first paid invoice
Suppose a partner sends a trial visitor on October 5. The application records referral R17, user U42 and the agreed 30-day eligibility window. On October 12, U42 starts Checkout Session CS9 for a monthly plan. The Session references checkout attempt A6; the resulting subscription references U42 through server-side mapping. When a $100 qualifying invoice is paid, a 20% first-payment commission policy creates a $20 pending entry. The next retry of the same webhook produces no second entry because the invoice key already exists.
If the invoice is subsequently refunded, a separate negative adjustment reverses the eligible amount according to policy. These numbers illustrate a possible business rule, not Stripe's or any affiliate platform's default. For further implementation detail, see affiliate webhook integration checks.
Implementation and QA checklist
Test a new signup, an existing customer, abandoned Checkout, duplicate event delivery, delayed payment confirmation, trial-to-paid conversion, plan upgrade, renewal and refund. For every test, verify that the right partner is attached, only eligible paid amounts earn commission, and the original evidence can be retrieved. Test the same browser and a fresh browser, with consent states respected. Review the Stripe object IDs visible in your own database and confirm that no public URL reveals a private identifier.
Before production, reconcile a sample of paid Stripe invoices against the commission ledger and document exceptions. A good implementation can explain why a specific invoice earned, did not earn or reversed a commission without relying on screenshots or guesswork.
A successful Stripe Checkout handoff is only the start of the commission decision. Our invoice finalization versus paid-event guide explains when a referred subscription invoice becomes eligible for commission.
Common questions
Can client_reference_id hold an affiliate ID?
It can hold a reconciliation string, but an opaque internal checkout ID is usually safer. The application should validate the actual affiliate relationship and eligibility on the server.
Does Session metadata automatically appear on a subscription?
No. Stripe documents separate nested metadata parameters for related objects. Set and verify the metadata on the object you need.
Is checkout.session.completed enough to release payment?
Not by itself for every payment method or business policy. Check successful payment or invoice state and any approval or refund hold.
Sources and editorial method
This guide is based on public Stripe documentation and a proposed engineering control model, not a claim that SaaSAlways tested a live Stripe integration. Verify current API behavior against your Stripe API version: Checkout Session object, metadata, and fulfillment. No vendor paid for inclusion.