Full and Partial Refunds

Issuing refunds through CrissCross

Overview

Refunding transactions is a crucial aspect of managing a successful merchant operation. CrissCross supports both full and partial refunds, allowing merchants to process refunds directly through the same payment rails used for the original transactions.

How CrissCross Executes Refunds

You always call the same POST /payment/refunds endpoint, but under the hood CrissCross executes a refund in one of two ways depending on what the originating payment provider supports:

  1. Provider refund. When the originating provider exposes a refund API, CrissCross calls it directly. This is the preferred path because it reverses the original movement on the rail it came in on.
  2. Payout refund. When the originating provider does not support refunds, CrissCross automatically converts the refund into a payout back to the original destination (the payer’s mobile wallet, bank account, etc.). This is particularly common for mobile money, where many providers expose payouts but not refund APIs, and is also used for bank payment methods when we hold the full destination account details.

Two practical consequences:

  • No time limit on payout refunds. Provider refund windows (typically 90–180 days, sometimes shorter) only apply when CrissCross takes the provider-refund path. Payout refunds can be issued whenever the destination is still valid.
  • Unified accounting. Both types are tracked as refunds against the original transaction (they appear in refundTransactionIds and contribute to totalRefundedValue on the session). You cannot over-refund a customer regardless of which mechanism executes, because the same balance is enforced for both.

The mechanism CrissCross chose for any given refund is visible on the returned refund transaction; consumers do not need to differentiate between the two paths to issue or track refunds correctly.

Refund Requirements

  • Available Balances: To process refunds, merchants must maintain sufficient balances with their payment processors in the relevant markets. Payout refunds additionally require sufficient payout balance for the destination currency.
  • Transaction Eligibility: Refunds can only be issued against transactions that have been successfully captured and settled. Provider-refund windows apply only on the provider-refund path; payout refunds are not subject to a CrissCross-imposed time limit.

Creating a Refund

Refunds are created against a checkout session using POST /payment/refunds. The request body takes:

  • sessionId — the session whose transaction you want to refund.
  • refundValue — an object with minorAmount (the refund amount in minor units, e.g. cents) and currency (ISO 4217). The currency must match the original transaction. This mirrors the destinationValue shape used on payouts.
  • originalTransactionId (optional) — only needed when a session has more than one refundable transaction. If omitted, CrissCross resolves to the single refundable transaction on the session.
  • reason (optional) — free-form note recorded for reporting and dispute defense.

A refund is itself a transaction in CrissCross, so the response follows the same shape as other transaction responses: transactionId, status, and message, plus refund-specific fields:

  • transactionId — the refund’s own transaction identifier. Use this to retrieve the refund or correlate webhook events.
  • originalTransactionId — the transaction on the session that was refunded. Returned even when the request omitted it, so callers can see which transaction was selected.
  • sessionId and refundValue — echoed back from the request.

Refunds Are Asynchronous

Refund creation always returns a record with status: PENDING. The refund is then processed against the underlying rail and transitions to COMPLETED or FAILED. There are two ways to observe the transition:

  • Poll GET /payment/refunds/{transactionId} using the returned transactionId.
  • Subscribe to the refund.succeeded and refund.failed webhook events.

Full Refund

A full refund returns the entire remaining refundable balance. Pass the original transaction amount in refundValue.minorAmount:

1{
2 "sessionId": "01951c8a-7c3d-7e1f-9d4a-2b3c4d5e6f70",
3 "refundValue": {
4 "minorAmount": 10000,
5 "currency": "NGN"
6 },
7 "reason": "Customer returned the item"
8}

Partial Refund

Partial refunds return only a portion of the transaction amount, useful for partial returns or post-purchase discounts. Pass the partial amount in refundValue.minorAmount:

1{
2 "sessionId": "01951c8a-7c3d-7e1f-9d4a-2b3c4d5e6f70",
3 "refundValue": {
4 "minorAmount": 2500,
5 "currency": "NGN"
6 },
7 "reason": "Partial return — one of two items"
8}

Disambiguating Multiple Transactions

If a session has more than one refundable transaction (for example, a retry that captured separately, or a split tender), the API returns 409 and requires originalTransactionId:

1{
2 "sessionId": "01951c8a-7c3d-7e1f-9d4a-2b3c4d5e6f70",
3 "originalTransactionId": "01951c8a-8b4c-7d2a-8f1e-5d6c7b8a9e10",
4 "refundValue": {
5 "minorAmount": 2500,
6 "currency": "NGN"
7 }
8}

Retrieving a Refund

Use GET /payment/refunds/{transactionId} with the transactionId returned from creation to check the current status. The response shape matches the create response, with status reflecting the latest state (PENDING, COMPLETED, or FAILED).

Where Refunds Surface on Other Objects

Refunds are linked back from the records they affect so you don’t have to query refunds separately to understand the state of a session or transaction:

  • On the parent transaction: refundTransactionIds is a list of the transactionId of every refund processed against that transaction. Pass any of them directly to GET /payment/refunds/{transactionId}.
  • On the session: totalRefundedValue is a { minorAmount, currency } object reflecting the cumulative amount refunded across all refunds on the session. Use this to check remaining refundable balance before issuing further partial refunds.

Refund Notifications

When refunds are processed, CrissCross can trigger notifications for:

  • Successful Refunds: Confirmations sent to both merchants and customers.
  • Balance Alerts: Notifications for top-ups when balances with processors are insufficient to cover the refund.

Best Practices

  • Maintain Adequate Balances: Regularly monitor and top up your balances with payment processors to ensure smooth refund transactions.
  • Communicate with Customers: Keep customers informed about the status of their refunds to maintain trust and satisfaction.
  • Monitor Refund Trends: Analyze refund patterns to identify potential issues with products or services early on.

Conclusion

Efficiently managing refunds is essential for maintaining customer satisfaction and operational compliance. CrissCross provides robust tools to handle full and partial refunds, ensuring merchants can manage their financial transactions effectively.