KickrailBlog
← All posts
Building in public19 Oct 20265 min read

Three affiliate attribution bugs a real end-to-end test found

Unit tests passed. Then we ran real Stripe checkouts through Kickrail and found code-only sales credited to nobody, a lost first invoice, and codes stranded on an old coupon. What went wrong and how each was fixed.

Kickrail team

Kickrail is open source, so here is a post we'd rather not have to write. Our unit tests built Stripe events by hand, from the documentation. This week we ran the whole flow instead: real test-mode checkouts, real webhooks forwarded from Stripe, real promotion codes. Three bugs fell out. All three are fixed and live.

1. A sale made with only a code was credited to nobody

The promise of creator codes is that a listener types JANE20 at checkout and Jane gets the commission, with no link click.

On a paid invoice, we read the discounts to find the promotion code. Our test fixtures had each discount as an object with the promotion code inside. Real invoice.paid events list discounts as ids, plain di_... strings. The lookup found nothing, so a code-only sale was never attributed.

Fix: when an invoice carries discounts, fetch it from Stripe with the discounts expanded, then read the promotion code.

Lesson: fixtures written from the docs test your reading of the docs, not Stripe.

2. The first subscription invoice was lost

For a referred visitor, the click id travels into Stripe Checkout as client_reference_id, which lives on the checkout session. We created the referral when checkout.session.completed arrived and credited invoices after that.

Stripe often sends invoice.paid for the first invoice before checkout.session.completed. At that moment the customer isn't tied to anyone, so the first month's commission was skipped. Renewals worked; the first payment, often the largest, didn't.

Fix: when checkout completes and creates the referral, it also credits that session's invoice. Commissions are keyed by invoice id, so whichever event arrives second can't credit it twice.

3. Changing the discount stranded every code

Merchants change offers: 20% off becomes 30% off for launch week. A Stripe promotion code is bound to one coupon, so when a campaign's coupon changed, every affiliate code kept pointing at the old one.

Fix: on a coupon change, Kickrail deactivates the old promotion codes, recreates them with the same names on the new coupon, and keeps the old ids so a customer who redeemed the old code is still credited. Removing the coupon switches the codes off.

What changed in how we test

Each of these fixes shipped only after a full end-to-end run against Stripe test mode: 54 checks covering links, codes, Checkout, refunds, renewals, payouts, the API, the MCP server, exports and the audit log. The unit tests now use the event shapes Stripe actually sends.

If you run an affiliate program on any tool, it's worth one afternoon to buy your own product through an affiliate code in test mode and check the commission lands. That's how we found these.