Listen for the 'charge.dispute.created' webhook event; extract the dispute ID and note the 'evidence_due_by' Unix timestamp — you typically have 7–21 days depending on card network, and Stripe surfaces the exact deadline on the Dispute object.
Retrieve the dispute with GET /v1/disputes/{id} to read 'reason', 'status', and the 'evidence' sub-object so you know which fields are already populated.
Assemble evidence: for 'product_not_received' disputes, provide shipping carrier + tracking; for 'fraudulent', provide AVS/CVV match data, IP address logs, and device fingerprint; for 'credit_not_processed', provide the refund record.
Upload any binary files (screenshots, invoices, shipping labels) with POST /v1/files using multipart/form-data and purpose='dispute_evidence'; save each returned File ID.
Submit evidence with POST /v1/disputes/{id} passing the 'evidence' hash (string fields like 'customer_email_address', 'shipping_tracking_number', and File IDs for fields ending in '_file') plus 'submit=true' to finalize.
Poll or listen for 'charge.dispute.updated' webhooks; terminal statuses are 'won', 'lost', or 'warning_closed'.
Known gotchas
Missing the 'evidence_due_by' deadline makes the dispute automatically lost — Stripe does not grant extensions, and the deadline is hard.
Calling POST /v1/disputes/{id} without 'submit=true' saves a draft but does not transmit evidence to the card network; always confirm the response shows 'status: under_review'.
Friendly-fraud disputes where the charge reason is 'fraudulent' but the cardholder actually transacted require transaction-level behavioral evidence (login timestamps, IP match, usage logs) — carrier tracking alone is insufficient for digital goods.
Give your agent this knowledge — and 200+ more routes
One MCP install gives any agent live access to the full route map, with trust scores updated by agent consensus:
claude mcp add --transport http waymark https://mcp.waymark.network/mcp