Bonaventure OgetoBy Bonaventure Ogeto|

Refunding Customers via Transfer vs Refund API

The Refund API reverses the original Paystack transaction, crediting the customer through the same payment channel they used. Transfers send new money from your balance to a recipient account. Use the Refund API for standard customer refunds (simpler, cleaner accounting). Use transfers when you need to refund to a different account, refund after the refund window, or send money that is not tied to a specific transaction.

Two Approaches to Returning Money

When a customer needs money back (order cancelled, product returned, service not delivered), you have two mechanisms on Paystack.

Refund API: POST to /refund with the original transaction reference. Paystack reverses the charge through the same payment channel. If the customer paid by card, the refund goes back to their card. If they paid via bank transfer, it goes back to the source account. The customer sees a reversal, not a new payment.

Transfer: Create a transfer recipient with the customer's bank details and send a transfer. The customer sees a new credit in their account. This is completely independent of the original transaction.

The right choice depends on your situation. Most standard refunds should use the Refund API. Transfers are for the edge cases where the Refund API does not work.

Using the Refund API

// Full refund
async function refundTransaction(transactionReference) {
  var response = await fetch('https://api.paystack.co/refund', {
    method: 'POST',
    headers: {
      Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      transaction: transactionReference,
    }),
  });

  var data = await response.json();
  if (!data.status) {
    throw new Error('Refund failed: ' + data.message);
  }

  return data.data;
}

// Partial refund
async function partialRefund(transactionReference, amountMinorUnit) {
  var response = await fetch('https://api.paystack.co/refund', {
    method: 'POST',
    headers: {
      Authorization: 'Bearer ' + process.env.PAYSTACK_SECRET_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      transaction: transactionReference,
      amount: amountMinorUnit, // Refund this amount only
    }),
  });

  var data = await response.json();
  return data.data;
}

The Refund API is straightforward. You reference the original transaction, and Paystack handles the rest. The refund goes back to the customer through the same channel they paid with. You do not need to know or collect the customer's bank details.

Refunds are subject to a time window. Check Paystack's documentation for the current refund window, which may vary by payment channel and market. If the window has passed, the Refund API will reject the request, and you will need to use a transfer instead.

Transfer-Based Refunds

async function refundViaTransfer(customerId, amountMinorUnit, originalOrderId) {
  // Get or create a recipient for the customer
  var customer = await db.customers.findById(customerId);

  var recipientCode = customer.paystackRecipientCode;
  if (!recipientCode) {
    // Customer does not have a recipient on file
    // You need to collect their bank details
    throw new Error('Customer bank details needed for transfer refund');
  }

  var reference = 'refund_' + originalOrderId + '_' + Date.now();

  var result = await initiateTransfer(
    recipientCode,
    amountMinorUnit,
    'Refund for order #' + originalOrderId,
    reference
  );

  // Record the refund
  await db.refunds.create({
    customerId: customerId,
    orderId: originalOrderId,
    amount: amountMinorUnit,
    method: 'transfer',
    reference: reference,
    transferCode: result.transferCode,
    status: 'processing',
  });

  return result;
}

Transfer-based refunds require the customer's bank details, which you may not have. If the customer paid by card, you have their card info but not their bank account. You would need to collect bank details separately, which adds friction to the refund process. This is one of the main reasons the Refund API is preferred for standard refunds.

When to Use Which Approach

Use the Refund API when:

  • The refund is for a specific transaction and you have the transaction reference
  • You are within the refund time window
  • You want the money to go back to the same payment method the customer used
  • You want cleaner accounting (the refund is linked to the original transaction)
  • You need partial refunds

Use transfers when:

  • The refund window has passed
  • The customer wants the money sent to a different account than they paid from
  • The refund is not tied to a specific Paystack transaction (goodwill credit, compensation)
  • The original payment was via a channel that does not support refunds
  • You are refunding a split payment where the subaccount has already been settled

Accounting Differences

The accounting treatment differs significantly between the two approaches.

Refund API: The refund is a reversal of the original revenue. In your ledger, it reduces the gross revenue for the period. The Paystack fee may or may not be returned depending on the refund policy. Your reconciliation is clean because the refund is linked to the original transaction ID.

Transfer refund: The transfer is a new outgoing payment, recorded as an expense or a contra-revenue entry. It is not automatically linked to the original transaction in Paystack's records. You must maintain the link in your own database. Your accountant sees two separate entries: the original revenue and the refund expense.

For businesses that process many refunds, the Refund API creates cleaner financial records. For occasional refunds, either approach works as long as your internal tracking links the refund to the original transaction.

Refunding Split Payment Transactions

Split payment refunds are the trickiest case. If a customer paid for an order that was split between your account and a vendor subaccount, and the vendor has already been settled, the refund comes entirely from your main balance.

The Refund API processes the refund from your balance. You then need to recover the vendor's portion through your own arrangement (deduct from their next payout, request a return, etc.).

Transfer-based refunds for split payments work the same way: the money comes from your balance, and recovering the vendor's portion is your problem.

This is why many marketplaces use delayed settlement. Hold the vendor's settlement until the refund window closes, so you can process refunds without being out of pocket. For delayed settlement patterns, see delayed settlement patterns for marketplaces.

Handle Refunds Like a Professional

Refunds are a fact of business. Handling them quickly and correctly builds customer trust. The way you return money says as much about your product as the way you accept it.

The McTaba bootcamp covers the full payment lifecycle, including the refund and dispute flows that many tutorials skip.

Create a free McTaba account

Key Takeaways

  • The Refund API reverses the original transaction through the same payment channel. The customer sees a credit from the original merchant.
  • Transfer-based refunds send new money to a bank account or mobile wallet. The customer sees a new credit, not a reversal of the original charge.
  • Refund API is simpler for accounting: it reduces your revenue for the refunded transaction. Transfers create a separate expense entry.
  • Use the Refund API for standard refunds within the refund window. Use transfers when the refund window has passed or you need to refund to a different account.
  • Partial refunds are supported by the Refund API. You can refund a portion of the original transaction amount.
  • Both approaches deduct from your Paystack balance. Ensure sufficient funds before initiating either type of refund.

Frequently Asked Questions

Does Paystack refund the processing fee when I issue a refund?
Paystack fee refund policy may vary by market and over time. Check the current Paystack documentation or your account terms for the latest policy on fee refunds. Some payment processors refund the fee on full refunds but not partial refunds.
How long does a Refund API refund take to reach the customer?
Refund processing time depends on the payment channel. Card refunds can take 5-10 business days to appear on the customer statement, depending on the issuing bank. Bank transfer refunds may be faster. Communicate expected timelines to customers to set expectations.
Can I refund a transaction that was paid via M-Pesa?
Check Paystack documentation for current M-Pesa refund support. If the Refund API does not support the specific payment channel, use a transfer to the customer M-Pesa wallet as an alternative.

Ready to build real-world apps?

Join the McTaba Labs full-stack marathon (4 months full-time · 6 months part-time). Learn M-Pesa, USSD, and WhatsApp engineering while shipping 8 production apps.

Apply to the McTaba Marathon