Official documentation reviewed 7 November 2026 ยท Documentation-based guide
How should Stripe disputes affect SaaS affiliate commissions?
Treat a Stripe dispute as a payment-risk event, not automatic proof that an affiliate earned an invalid commission. When a dispute opens, identify the original payment, locate the related invoice or subscription, and place the affected commission on hold according to your program terms. Reverse or restore the commission only after the dispute outcome and the actual funds movement are reconciled.
Stripe sends dispute events through webhooks, but its Dispute object exposes a Charge and a nullable PaymentIntent rather than a direct invoice or subscription reference. Your integration therefore needs a reliable payment-to-billing mapping before it can adjust the correct affiliate ledger entry.
This is different from a failed renewal or scheduled cancellation. See the Stripe failed-payment commission hold guide, the Stripe subscription cancellation guide and the Stripe Billing affiliate software buyer guide for related implementation decisions.
Which Stripe dispute events should you handle?
Stripe’s event catalogue includes several dispute events. They represent different points in the lifecycle and should not all trigger the same financial adjustment.
| Event | Meaning | Affiliate-ledger response |
|---|---|---|
charge.dispute.created |
A customer disputes a charge with their bank. | Find the payment and place the related commission on hold under your policy. |
charge.dispute.updated |
The dispute is updated, usually with evidence. | Refresh the dispute record; do not create another commission adjustment. |
charge.dispute.closed |
The dispute closes with a status such as won, lost or warning_closed. | Record the outcome and apply the policy for the final status. |
charge.dispute.funds_withdrawn |
Funds are removed from the Stripe balance because of a dispute. | Reconcile the actual funds movement against the payment and dispute ID. |
charge.dispute.funds_reinstated |
Funds are reinstated after a dispute is closed; this can include partially refunded payments. | Release or restore the commission only if the agreement and final payment record allow it. |
Use the event catalogue as the source of truth for event names and descriptions. The dispute status and funds movement are related but distinct facts. A status change should not be assumed to mean the money has already settled back into the account.
Map a dispute to the correct invoice and subscription
Start with the dispute ID and its payment references. Stripe documents that a dispute contains a Charge and a nullable PaymentIntent, but does not include a direct invoice or subscription reference. Use the Charge or PaymentIntent to locate your internal payment record, then resolve the associated Stripe invoice and subscription from the billing data you stored when the payment was created.
- Store the Stripe dispute ID, Charge ID and PaymentIntent ID where available.
- Look up the original payment in your internal billing ledger.
- Resolve the invoice ID, subscription ID, customer ID and affiliate referral ID from that payment record.
- Confirm whether the dispute is full or partial and record the disputed amount and currency.
- Attach the adjustment to the original commission entry rather than creating a new unrelated debit.
Do not use customer email as the only join key. Email addresses can change, and the same customer may have multiple subscriptions or payments. Use Stripe object IDs and your own immutable internal references.
Define hold, reversal and restoration rules
Write the policy before automating ledger entries. A practical model has three stages:
- Hold: When the dispute is created, freeze the affected commission from payout while the payment is under review. Keep the original referral and commission calculation visible.
- Reverse: If the dispute is lost and the payment is not recovered, create a linked negative adjustment according to the agreement. Do not delete the original commission record.
- Restore: If the dispute is won and the funds are reinstated, release the hold or create a linked restoration entry if a reversal was already posted.
The program’s contract should define whether a dispute creates an immediate hold, when a reversal is final, how partial disputes are calculated and how late wins are handled. Because a dispute can remain open while evidence is reviewed, define a payout hold and review period in your program terms rather than assuming that a webhook status alone settles the financial outcome.
Do not assume every dispute is a full reversal. Stripe documents that disputed amounts can be partial, can differ from the original payment, and can involve multiple disputes against one payment. Keep each dispute ID separate even when several disputes reference the same Charge or PaymentIntent.
Make webhook processing secure and idempotent
Stripe requires webhook signature verification using the raw request body, the Stripe-Signature header and the endpoint signing secret. Do not parse and re-serialize the body before signature verification. Return a successful 2xx response quickly, then move longer reconciliation work to a queue or background job.
- Verify the signature before accepting an event.
- Store the Stripe event ID and dispute ID with a unique constraint.
- Make every ledger adjustment idempotent so a repeated delivery cannot reverse a commission twice.
- Fetch the current dispute or payment object when an event arrives late or the local state is unclear.
- Keep an append-only audit trail of the original commission, hold, reversal and restoration.
Stripe documents that webhook endpoints can receive multiple event types and that a single endpoint can process several event types. Subscribe only to the dispute events your integration needs, and keep the handler small enough to acknowledge events reliably.
Worked example: a $100 payment with a $20 commission
Assume a SaaS customer pays $100 and the affiliate’s agreed commission is 20% of eligible collected revenue.
| Lifecycle point | Payment state | Commission ledger |
|---|---|---|
| Payment succeeds | $100 collected | Record $20 as pending under the normal approval rules. |
| Dispute is created | Payment is disputed | Place the $20 entry on hold; preserve its original ID and referral. |
| Dispute is lost | Issuer decision is final against the business | Post a linked -$20 adjustment if the program terms permit reversal. |
| Dispute is won and funds are reinstated | Funds return to the business | Release the hold or restore the commission, subject to the agreement. |
If only $40 of the $100 payment is disputed, do not automatically reverse the full $20. Apply the documented partial-dispute rule. The example uses simple proportional arithmetic; your agreement should state whether the commission base is gross, net of discounts, or net of other adjustments.
Handle the cases that cause reconciliation errors
- Multiple disputes on one payment: Stripe assigns a unique ID to each dispute. Do not deduplicate by Charge ID alone.
- Partial dispute: Store the disputed amount and currency separately from the original payment amount.
- Late event delivery: Use event IDs and retrieve current objects when local state is behind.
- Refund plus dispute: Reconcile the refund and dispute separately so the same amount is not deducted twice.
- Dispute won but funds not yet reconciled: Keep the adjustment pending until the relevant funds event or balance record confirms the money movement.
For refund reserves and negative balances, see SaaS affiliate refund reserve policy and how affiliate commission clawbacks work.
Acceptance checklist
- Every dispute can be traced to one or more payment records and the original referral.
- Charge and PaymentIntent references are stored; invoice and subscription are resolved from the billing ledger.
- Dispute status and funds movement are separate fields.
- Duplicate webhook deliveries do not create duplicate holds or reversals.
- Partial disputes use the contract’s stated calculation rule.
- Lost, won and late-win outcomes are reconciled with the final balance movement.
- Finance can trace each adjustment to the original commission and dispute ID.
Frequently asked questions
Does charge.dispute.created mean the affiliate commission is permanently lost?
No. It signals that the payment is disputed. A hold is safer than a final reversal until the dispute outcome and program policy are known.
Does the Stripe Dispute object contain a subscription ID?
Stripe documents a Charge and a nullable PaymentIntent reference, not a direct invoice or subscription reference. Resolve the subscription through your payment and billing records.
Should I reverse a commission when funds are withdrawn?
Use your agreement to decide whether the event creates a hold or a provisional adjustment. Reconcile the final dispute outcome and funds movement before treating the reversal as final.
Can one payment have multiple disputes?
Stripe says it is possible, although uncommon. Track each dispute by its own ID and reconcile the amount and currency for each one.
Sources and editorial disclosure
Primary references: Stripe Disputes API, Stripe event types, Stripe dispute lifecycle, Stripe webhooks and responding to disputes. Reviewed 7 November 2026.
This guide is documentation-based and does not claim a live Stripe integration test. Commission treatment is a program-policy decision, not a Stripe feature or legal recommendation.