Coupon code affiliate tracking: how affiliate codes get credited
How coupon code affiliate tracking works: what an affiliate code is, how to read it from a Stripe payment, and which limits stop a code from leaking.
Muzahid Maruf, FounderUpdated
On this page
- 01What is an affiliate code?
- 02How does a code become a commission?
- 03Should you use an affiliate code or an affiliate link?
- 04How do you set up coupon code affiliate tracking in Stripe?
- 05How does coupon duration change the numbers?
- 06Which settings stop a code from leaking?
- 07How does TrackRev track coupon codes?
- 08When does another tool fit better?
Explore with AI
Opens this article inside the chosen assistant with a ready-made prompt.
Coupon code affiliate tracking is a method that credits a sale to an affiliate through the discount code the customer typed at checkout, with no click involved. For example, Nora's code NORA20 takes 20% off a $49 monthly plan.
The customer pays $39.20, Stripe records the code on the invoice, and the tracking system looks the code up and credits Nora $11.76 at a 30% commission rate.
Codes reach sales a link cannot: a podcast read, a video description, or a phone click followed by a laptop purchase 8 days later.
This guide covers a 6-step Stripe setup, a Node.js lookup, the year-one cost of each coupon duration and the settings that stop a code from leaking, using Stripe and WebKit documentation from 2026.
Key takeaways
- A coupon code credits an affiliate only when it belongs to that partner alone. A code every partner shares discounts the sale and credits nobody.
- Create one Stripe coupon, then one promotion code per affiliate, and read the code from the invoice's expanded discounts or from total_details.breakdown.
- A once coupon rides on the first of 12 yearly invoices only, so renewal commission on code sales depends on how long the discount runs.
- Cap every code: 200 redemptions on a forever coupon can commit $28,224 of commission in year one.
What is an affiliate code?
An affiliate code is a discount code issued to one affiliate, so the customer gets a price break and the partner who owns the string gets the commission.
A code works only while unique: a code shared by all 40 of your partners credits none of them. Stripe keeps the discount and the code apart.
A coupon holds the discount (percent_off or amount_off, lasting once, repeating or forever), and a promotion code is the customer-facing string wrapped around the coupon, so many codes can share one coupon, per Stripe's coupon documentation (2026).
One 20% coupon plus a promotion code per partner gives per-affiliate tracking.
How does a code become a commission?
According to the Discount object reference (2026), a redeemed code leaves a Discount object holding the promotion_code ID, and where you read the object depends on how the customer paid.
A subscription in Stripe Checkout shows the code in the invoice's discounts after invoice.paid. A one-time payment shows it in total_details.breakdown on the Checkout Session.
A Payment Link behaves like Checkout, and a plan change in the customer portal shows it in the subscription's discounts.
Invoice discounts return as IDs until expanded, and each promotion_code is an ID too, so the handler makes one extra call for the typed string.
| Payment flow | Where the code appears | What to watch |
|---|---|---|
| Subscription in Stripe Checkout | The invoice's discounts, after invoice.paid | A subscription holds up to 20 discounts, coupons and codes combined |
| One-time payment in Stripe Checkout | total_details.breakdown on the Checkout Session | The breakdown is not returned unless you expand it |
| Payment Link | Same as Checkout | Needs allow_promotion_codes on the link |
| Plan change in the customer portal | The subscription's discounts | Only with portal promotion codes enabled |
Each row of the table has a limit: a Stripe Billing subscription holds up to 20 discounts, coupons and codes combined, and the breakdown is not returned unless you expand it.
import Stripe from "stripe"; const stripe = new Stripe(process.env.STRIPE_SECRET_KEY); // partnerByCode maps an uppercased code to a partner, e.g. { NORA20: "ptn_81" }export async function partnerForInvoice(invoiceId, partnerByCode) { const invoice = await stripe.invoices.retrieve(invoiceId, { expand: ["discounts"], }); for (const discount of invoice.discounts) { if (!discount.promotion_code) continue; const promo = await stripe.promotionCodes.retrieve(discount.promotion_code); const partnerId = partnerByCode[promo.code.toUpperCase()]; if (partnerId) return { partnerId, code: promo.code }; } return null; // no code on this invoice}Should you use an affiliate code or an affiliate link?
A link is a click record and a code is a typed string, so each catches sales the other misses. Use both, because the two fail under different conditions.
In Apple Safari a cookie created in JavaScript lasts 7 days without user interaction and 24 hours after link decoration from a classified tracker, while a code still works on day 8.
A phone click followed by a laptop purchase loses the cookie, and a buyer who skips the code field loses the code.
Podcasters and video creators rarely send clicks, while bloggers and newsletter authors send clicks that give you a conversion rate. Both caps come from Intelligent Tracking Prevention, per WebKit's tracking prevention policy.
Safari ITP and SaaS attribution covers the funnel effect.
| Situation | Link and cookie | Code |
|---|---|---|
| Buyer returns 8 days after clicking in Apple Safari | A cookie created in JavaScript is deleted after 7 days without a visit | Credited at purchase |
| Landing from a decorated link in Apple Safari | The cookie is capped at 24 hours | Unaffected |
| Click on a phone, purchase on a laptop | The cookie stays on the phone | Credited if the buyer remembers it |
| Podcast read or video description | 0 clicks to record | Credited if the buyer types it |
| Buyer skips the code field | Credited by the cookie | No credit |
| Partner wants click-through rates | Full funnel visible | No click data |
What if the link and the code belong to different partners?
If a buyer arrives through Nora's link and types Priya's code, 2 partners claim 1 sale worth $39.20 on the $49 plan, and crediting both at 30% commits $23.52, or 48% of the list price.
Settle the rule before launch, in writing, in the Partner Terms. I would let the code win, since typing is deliberate and a cookie is passive.
TrackRev has no precedence setting today, because we built it to write at most 1 commission per partner per order, so a click and a code owned by different partners credit both.
Stripe's settings also know nothing about the partner, so a code works for its owner too, and preventing affiliate self-referral fraud covers the checks. See how affiliate tracking works for the cookie side.
How do you set up coupon code affiliate tracking in Stripe?
The Stripe setup is a 6-step process. Build in test mode first, because Stripe's testing guide lists the test card 4242 4242 4242 4242 with any future expiry date and any 3-digit CVC.
First, create one coupon per offer in the Stripe Dashboard or API, with percent_off or amount_off and a duration: once covers 1 invoice, repeating with duration_in_months covers a set span, and forever covers every invoice.
Second, call POST /v1/promotion_codes with the coupon ID and a code such as NORA20. Per the 2026 promotion code reference, codes use letters, digits and dashes and are case-insensitive.
Third, set allow_promotion_codes=true on the Checkout Session, per Stripe's Checkout discount guide. A Payment Link has the same setting, and attribution through Stripe Payment Links covers the details. Fourth, store each string against its partner, uppercased on both sides.
Short strings avoid misheard pairs such as O and 0 or I and 1.
How do you read the code on every payment?
Reading the code is the fifth step: run the handler from your invoice.paid webhook, and for one-time payments read the Checkout Session with total_details.breakdown expanded.
Credit each invoice once, since Stripe's webhook guide says an event can arrive more than once. Pay on the amount the customer paid, because the discount shrinks the base.
On a $49 plan at 30% commission, a 20% coupon pays $11.76 on the amount paid but $14.70 on the list price, an overpayment of $2.94 per invoice.
Sixth, redeem a code on a subscription and on a one-time payment with the 4242 test card, then refund one payment and confirm its commission reverses.
| Coupon on a $49 plan | Customer pays | 30% of amount paid | 30% of list price | Overpayment per invoice |
|---|---|---|---|---|
| 10% off | $44.10 | $13.23 | $14.70 | $1.47 |
| 20% off | $39.20 | $11.76 | $14.70 | $2.94 |
| 30% off | $34.30 | $10.29 | $14.70 | $4.41 |
| 40% off | $29.40 | $8.82 | $14.70 | $5.88 |
| 50% off | $24.50 | $7.35 | $14.70 | $7.35 |
How does coupon duration change the numbers?
Coupon duration is the setting that decides how many invoices carry the code. NORA20 takes $9.80 off the $49 plan, so each coded invoice is $39.20 and Nora earns $11.76 at 30%.
Stripe drops a once coupon from the subscription's discounts after the first invoice finalizes, so the table assumes a tool that credits only invoices carrying the code.
The forever row pays Nora on all 12 invoices and leaves $329.28 of the $588 list price. The once row leaves $566.44 but pays on 1 invoice, because the 11 renewals are plain $49 invoices with no code.
Let the discount run as long as you intend to pay commission, or confirm your tool remembers the partner from the first sale. Affiliate tracking for recurring subscriptions goes deeper.
| Coupon duration | Coded invoices in year one | Customer pays | Discount given | Commission at 30% | Commission as share of list price | Revenue after commission |
|---|---|---|---|---|---|---|
| once | 1 of 12 | $578.20 | $9.80 | $11.76 | 2% | $566.44 |
| repeating, 3 months | 3 of 12 | $558.60 | $29.40 | $35.28 | 6% | $523.32 |
| repeating, 6 months | 6 of 12 | $529.20 | $58.80 | $70.56 | 12% | $458.64 |
| repeating, 9 months | 9 of 12 | $499.80 | $88.20 | $105.84 | 18% | $393.96 |
| forever | 12 of 12 | $470.40 | $117.60 | $141.12 | 24% | $329.28 |
Year-one totals for one customer on a $49 monthly plan with a 20% coupon and 30% commission on the amount paid. List price is $588.
Which settings stop a code from leaking?
A code posted publicly gets copied to coupon sites, and every redemption by someone the partner never reached pays commission for nothing. Price out the cap before launch.
Each redemption commits $11.76 on a once coupon and $141.12 on a forever coupon in year one, and a forever coupon also gives away $117.60 of discount (12 x $9.80).
TrackRev puts no cap on the commission it tracks, so the redemption cap is what protects your budget.
Stripe counts a trial subscription, even a canceled one, as a prior transaction, so a customer on a 14-day trial who types a first-time-only code at conversion is rejected. Ask for the code when the trial starts, on Day 1.
| Setting | What it does | Value for an affiliate code |
|---|---|---|
| first_time_transaction | Rejects customers with a prior payment or trial | true |
| max_redemptions | Caps total uses, at most the coupon's own cap, and a spent code cannot be reactivated | A count you would gladly pay commission on |
| expires_at | Ends redemption, no later than the coupon's redeem_by | Campaign end, such as 90 days after an episode airs |
Behavior from Stripe's coupon and promotion code documentation, October 2026.
| Redemption cap | Commission on first invoices | Commission over 12 invoices | Discount over 12 invoices |
|---|---|---|---|
| 25 | $294.00 | $3,528.00 | $2,940.00 |
| 50 | $588.00 | $7,056.00 | $5,880.00 |
| 100 | $1,176.00 | $14,112.00 | $11,760.00 |
| 200 | $2,352.00 | $28,224.00 | $23,520.00 |
| 500 | $5,880.00 | $70,560.00 | $58,800.00 |
Assumes every redemption is an active monthly customer on a forever coupon with recurring commission on.
How does TrackRev track coupon codes?
TrackRev is SaaS affiliate software for indie hackers and small teams, and we built it so you type the code against the partner on the Partners page or when you invite them.
The code is 3 to 40 characters of letters, numbers and dashes, unique within a program, matched without regard to case, and credited only to approved partners.
TrackRev reads codes but does not create them in your billing account, so make the Stripe promotion code first.
Affiliate programs need a paid plan: Indie at $29 a month for 1 site or Growth at $299 a year for up to 10 sites, with no limit on tracked revenue and 0% fees (pricing).
Commission is the program's rate on the amount paid after the discount, and a renewal pays only while the code is still on its invoice.
A refund reverses the commission (affiliate refund clawbacks covers partners already paid), and each program can set a payout hold of 0 to 180 days.
| Processor | What TrackRev reads | Setup note |
|---|---|---|
| Stripe | The promotion code on the invoice or Checkout Session, else the coupon's name then ID | Enter the same string on the partner |
| Paddle Billing | The discount's code | The API key needs Discount (Read) |
| Polar | The discount code | A coupon metadata field also works |
| Lemon Squeezy | Nothing | The order data TrackRev syncs carries no discount code |
| Creem and Dodo Payments | A coupon or coupon_code field in the checkout metadata (Creem) or payment metadata (Dodo Payments) | Your checkout has to pass the field |
When does another tool fit better?
Another tool fits better in 2026 when you want codes created for you. FirstPromoter's Create promo code endpoint is Stripe only and takes a code, a reward ID and a promoter campaign ID.
Tolt's Create Promotion Code endpoint takes a code, a type, a value and the partner_id that owns it.
For example, a team that wants one API call to mint NORA20 should compare both endpoints, because we built TrackRev to read codes, not create them.
Check any tool's Lemon Squeezy support before choosing, because TrackRev reads no discount code from Lemon Squeezy orders. A code-only sale also has no click behind it, so it carries no link or channel in reports.
Sources: docs.firstpromoter.com/api-reference-v2 · docs.tolt.com/promotion-codes
Found this useful? Share it.
Frequently asked questions
- A discount code that belongs to one affiliate, such as SAM15 for a newsletter author named Sam who offers 15% off. The payment record carries it after checkout, which traces the sale back to Sam.
- Sometimes. Vendors also use the phrase for a partner ID in a URL or the script that records clicks, so check which one is meant before comparing tools.
- You can, but customers cannot type a coupon, so it suits a discount your backend applies to one account. Only a promotion code can be limited to first-time customers or archived without deletion.
- Stripe retries undelivered events for up to 3 days in live mode, and sandbox events get 3 retries over a few hours. You can also resend an event from the Dashboard up to 15 days after it was created, or with the Stripe CLI up to 30 days after.
- Only while the discount stays on the invoice. Stripe removes a once coupon from the subscription's discounts after invoice 1 finalizes, so read the invoice that consumed it, not the subscription.
- No. The free plan covers link tracking only, with 50 links and 1,000 tracked events a month. Partner codes belong to the affiliate program, which starts on the Indie plan at $29 a month.

Written by
Founder, TrackRev.io & Contant.io
Muzahid Maruf founded TrackRev.io, SaaS affiliate software with no limit on tracked revenue, and Contant.io. He writes about affiliate programs.
Writes about Marketing attribution · Link tracking · Revenue analytics · SaaS growth
Run your affiliate program without a revenue cap.
Affiliate software for indie hackers and small SaaS teams: $29 a month flat, 0% fees, link tracking and revenue attribution built in. Free to start, no card.