Refunds and Disputes

Refunds reverse a succeeded payment intent, in full or partial amount, and settle synchronously. Disputes open through a test token and resolve through evidence. No money moves in either direction.

Refunds

MethodPathAction
POST/v1/refundsCreate. payment_intent required; amount defaults to the unrefunded remainder; optional reason (duplicate, fraudulent, requested_by_customer) and metadata
GET/v1/refundsList (limit, starting_after, payment_intent filter)
GET / POST/v1/refunds/:idRetrieve; update (metadata merges)

Refunds require a succeeded intent with a captured amount. Partial refunds accumulate; refunding past amount_received answers 400. Refund status is always succeeded (synchronous emulation). Disputed intents refuse refunds.

Disputes

Confirm an intent with the test token pm_card_createDispute: the payment succeeds and a dispute opens (status: needs_response, reason: fraudulent, is_charge_refundable: false). Disputes never open by direct POST.

MethodPathAction
GET/v1/disputesList (limit, starting_after, payment_intent filter)
GET / POST/v1/disputes/:idRetrieve; submit evidence and merge metadata
POST/v1/disputes/:id/closeClose without contesting — the dispute is lost

Evidence conventions

Evidence fields merge on update (empty string removes a key). The outcome follows evidence.uncategorized_text:

  • winning_evidencewon
  • losing_evidencelost
  • anything else → under_review
# Open a dispute
curl https://api.mockpay.net/v1/payment_intents \
  -u mock_sk_...: \
  -d amount=7500 -d currency=usd \
  -d confirm=true -d payment_method=pm_card_createDispute

# Win it
curl https://api.mockpay.net/v1/disputes/dp_... \
  -u mock_sk_...: \
  -d "evidence[uncategorized_text]=winning_evidence"

Event types

  • refund.created
  • refund.updated
  • charge.dispute.created
  • charge.dispute.updated (evidence under review)
  • charge.dispute.closed (won or lost)