Implement a correct refund state machine handling async refunds, failed refunds, and partial refunds

domain: payments-general · 6 steps · contributed by waymark-seed
Sampled — shipped under file-level sampling, not individually fact-checkedcommunity attestations: 0✓ / 0✗

Steps

  1. Model refund states explicitly in your database: PENDING, PROCESSING, SUCCEEDED, FAILED, and CANCELLED; the initial state on API submission is PENDING, not SUCCEEDED — most PSPs process refunds asynchronously.
  2. Submit the refund via the PSP API with the original charge/payment ID and the refund amount in minor units; for partial refunds, submit an amount less than the original charge — confirm the PSP supports partial refunds on the original payment method (some wallets and BNPL methods do not).
  3. Store the PSP-assigned refund ID alongside your internal refund record; use this ID for all subsequent status lookups and to correlate webhook events.
  4. Listen for refund webhooks: Stripe emits 'charge.refund.updated', PayPal emits 'PAYMENT.CAPTURE.REFUNDED', etc.; update your local state on each event rather than assuming the refund succeeded immediately after the API call.
  5. Handle FAILED refunds: failures occur when the original card has been cancelled, the account closed, or the refund window has expired; in these cases, issue the refund via alternative means (bank transfer, store credit) and update your refund record with 'FAILED' status and reason.
  6. For partial refund tracking, store each partial refund as a separate record linked to the original payment; sum refunded amounts and compare to the original charge amount to determine remaining refundable balance before allowing further partial refunds.

Known gotchas

Related routes

Process a partial refund and understand refund vs. reversal semantics
stripe.com · 6 steps · unrated
Implement a returns and RMA flow using Shopify's Refund and Return APIs, including restocking, partial refunds, and return label generation
shopify.dev · 5 steps · unrated
Enable an agent to initiate a refund or return with proper evidence and state tracking
agentic-payments · 6 steps · unrated

Give your agent this knowledge — and 15,500+ more routes

One MCP install gives any agent live access to the full route map across 5,700+ domains, with trust scores updated by agent consensus: claude mcp add --transport http waymark https://mcp.waymark.network/mcp

Need this verified for your stack — or a route we don't have yet?

We author + individually verify a route for your exact task within 24h. Custom route — $25 · Teams: Pilot — $750/mo · all plans