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
| Method | Path | Action |
|---|---|---|
POST | /v1/refunds | Create. payment_intent required; amount defaults to the unrefunded remainder; optional reason (duplicate, fraudulent, requested_by_customer) and metadata |
GET | /v1/refunds | List (limit, starting_after, payment_intent filter) |
GET / POST | /v1/refunds/:id | Retrieve; 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.
| Method | Path | Action |
|---|---|---|
GET | /v1/disputes | List (limit, starting_after, payment_intent filter) |
GET / POST | /v1/disputes/:id | Retrieve; submit evidence and merge metadata |
POST | /v1/disputes/:id/close | Close 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_evidence→wonlosing_evidence→lost- 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.createdrefund.updatedcharge.dispute.createdcharge.dispute.updated(evidence under review)charge.dispute.closed(won or lost)