Integration guides
Advanced features
Open in Markdown

Refunds, voids, and reversals

Learn how to manage your transactions by issuing refunds, voiding payments, or reversing authorizations.

Overview

Give money back to a customer, or cancel a payment, with one of three actions. Which one you use depends on where the payment is in its lifecycle:

Action Use it when What happens
Refund The payment is captured and refundable is true. The money goes back to the customer. You can refund the full amount or several partial amounts.
Void The payment is captured (SUCCESSFUL) and hasn't settled into a statement yet. The payment becomes VOIDED.
Reverse The payment is authorized but not captured. The hold on the customer's card is released and the payment becomes REVERSED.

Before you act, call find-payment and check the matching eligibility field:

  • refundable: True if the payment is eligible for a refund.
  • voidable: True if a captured (SUCCESSFUL) payment can be voided before it settles into a statement.
  • reversible: True if the authorization can be reversed (authorized but not yet captured).

A true flag means the action is allowed right now, but the call can still fail, for example because of an acquiring bank cut-off. Handle errors from these endpoints.

Payment statuses and the transitions between them are documented in Payment lifecycle.

Refunds

Refunds return funds to a customer for a payment that has already been captured. Full and partial refunds are supported, and you can issue multiple partial refunds against one payment. Each call to refund-payment creates a separate refund object. The amount is validated against the remaining refundable amount (also reduced by any disputed amount). Requesting more than remains returns AMOUNT_EXCEEDS_LIMIT.

Refunding a payment

To refund a payment, first verify that refundable is true. Then use refund-payment. Provide the payment_id of the transaction (your external_id is also accepted).

  • Full refund: If you don't specify an amount, the remaining refundable amount is returned to the customer.
  • Partial refund: Specify an amount in the smallest currency unit (e.g., satang for THB) to refund a specific portion of the payment.

Example: Partial refund

await fetch('https://api.reservepay.com/merchants/refund-payment', {
  method: 'POST',
  headers: {
    'Authorization': 'Bearer YOUR_API_KEY',
    'Api-Version': '2025-04-01',
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    payment_id: 'pay_1234567890',
    amount: 5000 // Refunds 50.00 THB
  })
})

Refund lifecycle

Each refund has its own rfn_ identifier and status:

PENDING → SUCCESSFUL
PENDING → FAILED

Save the refund ID returned by refund-payment. A successful response means the refund was accepted for processing, not that the customer has the money yet. Track it by polling find-refund until status is SUCCESSFUL or FAILED, or use list-refunds-by-payment to see every refund on a payment. Refunds don't send webhooks.

If the payment later gets a dispute, its status changes to DISPUTED even though the refunds still exist. Read the refund objects to know what was refunded.

Avoiding duplicate refunds

Send refunds for the same payment one at a time, never in parallel. If a refund call times out, check what already exists before you try again, as described in Idempotency and timeouts.

Eligibility for refunds

A payment can be refunded when it has been captured, still has an amount left to refund, and was made with a payment method that supports refunds. Otherwise refund-payment returns NOT_REFUNDABLE. Check refundable on each payment rather than assuming by payment method. For an authorization you haven't captured, reverse it instead.

Returning funds when refunds are not supported

When a payment's method doesn't support refunds, send the money back as a payout with send-payout-to-contact. Ask the customer for their bank account or PromptPay number first. A PromptPay payment doesn't tell you where to send money back.

The payout is a separate transaction. It comes out of your available balance, carries the normal payout fee, and doesn't change the original payment's status.

Use a unique payout external_id, such as return_order_12345_1, and store the link between that payout and the original payment in your system. See Sending funds for contact setup and destination fields.

Voids

A void cancels a captured payment before it settles, so no money moves and no refund is needed. You can usually void a payment until the end of the day it was captured, and only before it's included in a daily statement. Check voidable for the exact answer.

Check that voidable is true, then call void-payment with the payment_id. The payment becomes VOIDED. After the window closes, refund the payment instead.

Reversals

A reversal releases the hold on an authorized payment that you haven't captured. You can reverse a payment for up to 7 days after it was created. See Authorization and capture.

Check that reversible is true, then call reverse-payment with the payment_id. The payment becomes REVERSED.

Integrate further

Dive deeper into these advanced integration topics to unlock Reservepay's full potential with our in-depth guides.

Refunds, voids, and reversals

Issue refunds, void transactions before they settle, and reverse authorizations when needed.

Read the guide
Disputes

Find disputed payments, submit evidence, and respond before the deadline.

Read the guide
Authorization and capture

Separate authorization from capture to hold funds without charging. Perfect for pre-orders or reservations

Read the guide
Working with Terminal

Build your own POS, or work with our app by sending commands or using deep links.

Read the guide
Customer intelligence

Build profiles by attaching customer data. Gain insights, reduce fraud risk, and create experiences that drive loyalty.

Read the guide
Sending funds

Send payouts to your primary bank account or to your contacts via bank account, mobile number or national ID.

Read the guide
Real-time notifications

Stay informed about payment events with real-time webhooks. Automate your order processing, and more...

Read the guide
Payment lifecycle

Check payment statuses, available actions, refunds, and disputes.

Read the guide
Reconciliation

Filter payments and payouts, export CSVs, read balance holds, and reconcile daily statements.

Read the guide
Payment failure codes

Look up what each Reservepay failure code means when a payment is declined.

Read the guide

No account yet?

Start integrating all these amazing features into your app or website by creating your own merchant account today. It's free to sign up and only takes a few minutes to get started.