A chargeback reaches your code as a webhook, not a phone call. From that moment a clock is running, and in both Stripe’s and Adyen’s dispute APIs the defense is a one-shot submission: once the evidence goes to the card issuer, you cannot add to it. Building a chargeback API integration is mostly about getting three things right: catching the right events, mapping the dispute back to the order, and assembling a complete evidence package before anything is submitted.
This explainer compares how the two providers model a card dispute. It covers the mechanics a developer touches, not dispute fees or fraud-screening policy.
The dispute lifecycle in brief
Stripe’s guide to how disputes work describes the usual sequence. A cardholder asks their bank to reverse a payment. Some networks first send an inquiry, also called a retrieval or request for information, asking the merchant to explain the charge. If the case becomes a formal chargeback, the disputed amount is debited from the merchant’s balance and the merchant may respond with evidence.
The timing is set by card network rules, and the provider documentation gives ranges rather than one number. Stripe says networks typically let cardholders dispute within 120 days of the payment, with more time in some situations, such as a ticket for a future event. After a chargeback opens, the merchant usually has 7 to 21 days to respond, depending on the network. If evidence is submitted, the issuer typically takes 60 to 75 days to decide. A merchant that does not respond in time loses the dispute.
Which events to subscribe to
Stripe. Stripe sends charge.dispute.created when a dispute opens on the Dispute object, and its event list also includes charge.dispute.updated, charge.dispute.closed, charge.dispute.funds_withdrawn and charge.dispute.funds_reinstated. Inquiries use the same object with a warning_ prefix on the status: warning_needs_response, warning_under_review and warning_closed. Formal disputes move through needs_response and under_review to won or lost, and a prevented status covers a dispute stopped before it became a formal chargeback.
Adyen. Adyen’s dispute webhooks arrive on the Standard webhook once dispute events are enabled. Each message carries an eventCode, a pspReference for the dispute and an originalReference for the disputed payment. Adyen says the defense period starts with NOTIFICATION_OF_CHARGEBACK, and that you do not have to wait for the later CHARGEBACK event to begin. Other codes include REQUEST_FOR_INFORMATION, INFORMATION_SUPPLIED, SECOND_CHARGEBACK, CHARGEBACK_REVERSED, a set of pre-arbitration and scheme-arbitration codes, and DISPUTE_DEFENSE_PERIOD_ENDED. Most messages also carry a disputeStatus in additionalData, such as Undefended, Pending, Won or Lost; Adyen notes it is not returned for payments processed in Brazil.
One Adyen detail is easy to miss: CHARGEBACK_REVERSED is not a final win. Adyen says the issuer can still present a second chargeback, so the status stays Pending except in the Visa allocation flow.
The usual webhook hygiene applies. Verify signatures, as our comparison of webhook signature checks explains, and expect duplicates and out-of-order delivery, covered in our guide to payment webhook retries. A dispute handler should read the current state from the provider rather than trusting the order in which events arrived.
Linking a dispute to the order
Neither provider sends you the order. Stripe’s dispute API guide says the Dispute object exposes charge and a nullable payment_intent, but no direct reference to an invoice or subscription. Adyen gives the payment’s PSP reference in originalReference, and for CHARGEBACK_REVERSED, SECOND_CHARGEBACK and the two pre-arbitration result codes Adyen asks merchants to enable an extra webhook setting so that both references come through as expected.
That means your own system needs a reliable map from the provider’s payment ID to the order, the customer and the delivery records. Stripe also notes that one payment can carry more than one dispute, for example two items in the same order disputed separately, so key the case on the dispute ID rather than the payment ID.
Evidence: staged fields vs uploaded documents
The two APIs take evidence in different shapes.
| Stripe | Adyen | |
|---|---|---|
| Evidence format | Named fields on evidence, text or file IDs | Documents tagged with a defenseDocumentTypeCode |
| What to submit | Fields that fit the dispute reason | Documents required by the chosen defenseReasonCode |
| Staging | submit=false saves evidence without sending it | /supplyDefenseDocument uploads without sending |
| Final step | Update with submit=true (the default) | /defendDispute with the defense reason |
| Accept the loss | POST /v1/disputes/{id}/close | /acceptDispute |
Stripe evidence is a set of named fields such as customer_email_address, shipping_tracking_number, refund_policy and uncategorized_text. Text fields take strings; file fields take the ID of a file uploaded with the purpose dispute_evidence. The combined text across all fields is limited to 150,000 characters. The update endpoint has a submit flag, and its default is true. A request that sets one evidence field without submit=false sends the whole evidence hash to the issuer immediately. Stripe’s Dashboard guide is explicit that there is only one opportunity to submit, so an integration that collects evidence over several steps should stage with submit=false and send once at the end.
Adyen works from defense reasons. The Disputes API guide has you call /retrieveApplicableDefenseReasons with the dispute’s PSP reference and merchant account. The response lists each defense reason and the document types it needs, each with a requirementLevel of Required, OneOrMore, Optional or AlternativeRequired. Documents are uploaded as Base64 through /supplyDefenseDocument and can be removed with /deleteDisputeDefenseDocument. Nothing goes to the issuer until /defendDispute, after which Adyen says you can no longer add information.
Adyen also lists file limits: JPG and TIFF up to 10 MB, PDF up to 2 MB, with tighter rules for some schemes, including a 19-page limit for Mastercard defense documents. It refuses defense material that contains card numbers, Social Security numbers, passport copies or sensitive authentication data. The same caution applies to anything you attach on any provider: our explainer on PCI DSS scope covers why card numbers should not be sitting in your own files in the first place.
Inquiries deserve a response too
An inquiry looks less urgent because no money has moved, but Stripe warns that leaving one unanswered can be read as acceptance and can escalate into a formal, likely unwinnable chargeback. Stripe says American Express and Discover use this phase most often, while Mastercard and Visa no longer do. Answering an inquiry does not carry over: if it escalates, Stripe says a second response is needed for the chargeback. Adyen’s REQUEST_FOR_INFORMATION webhook has the same meaning and says no money is withdrawn at that stage.
A build checklist
- Subscribe to every dispute event, not only the creation event, and verify signatures.
- Store the provider’s dispute ID, payment ID, reason, status and evidence deadline on your own case record.
- Map the payment to the order, customer, delivery and communication records before the deadline starts to bite.
- Stage evidence (Stripe
submit=false, Adyen document uploads) and submit once. - Alert a person well before the deadline, since a missed deadline is an automatic loss.
- Track provider changes to dispute objects and events in our Stripe and Adyen API change records.





