Skip to content

CheckoutResult

CheckoutResult represents the outcome of a checkout. It uses a discriminated union (TypeScript), an enum (Swift), a sealed class (Kotlin), or a status enum on a result class (Dart) so you can exhaustively handle every case.

Status Web / React / React Native Flutter / iOS / Android
successful Yes Yes
cancelled Yes Yes
failed Yes Yes
pending Yes No

The pending status is only returned on web-based platforms where the browser can close before the provider confirms the transaction. On native platforms, the checkout always resolves to a terminal state.

type CheckoutResult =
| SuccessfulCheckoutResult
| CancelledCheckoutResult
| FailedCheckoutResult
| PendingCheckoutResult;
interface SuccessfulCheckoutResult {
status: "successful";
provider: string;
reference: string;
transactionId?: string;
message?: string;
raw: unknown;
}
interface CancelledCheckoutResult {
status: "cancelled";
provider: string;
reference?: string;
raw?: unknown;
}
interface FailedCheckoutResult {
status: "failed";
provider: string;
reference?: string;
error: SanwoErrorInfo;
raw?: unknown;
}
interface PendingCheckoutResult {
status: "pending";
provider: string;
reference?: string;
raw?: unknown;
}
const result = await sanwo({
amount: 500000,
currency: "NGN",
customer: { email: "customer@example.com" },
});
switch (result.status) {
case "successful":
console.log(`Paid! Ref: ${result.reference}`);
// result.transactionId, result.message, result.raw
break;
case "cancelled":
console.log("User closed checkout");
break;
case "failed":
console.error(`Error: ${result.error.message}`);
if (result.error.recoverable) {
// safe to retry
}
break;
case "pending":
// verify server-side using result.reference
console.log(`Pending — verify ref: ${result.reference}`);
break;
}
enum CheckoutStatus { successful, cancelled, failed }
class CheckoutResult {
final CheckoutStatus status;
final String? reference;
final String? transactionId;
final String? message;
final Map<String, dynamic> data;
CheckoutResult({
required this.status,
this.reference,
this.transactionId,
this.message,
this.data = const {},
});
}
final result = await sanwo(
context: context,
options: CheckoutOptions(
amount: 500000,
currency: 'NGN',
customer: CheckoutCustomer(email: 'customer@example.com'),
),
);
switch (result.status) {
case CheckoutStatus.successful:
print('Paid! Ref: ${result.reference}');
print('Transaction ID: ${result.transactionId}');
break;
case CheckoutStatus.cancelled:
print('User cancelled');
break;
case CheckoutStatus.failed:
print('Payment failed: ${result.message}');
break;
}
enum CheckoutResult {
case successful(SuccessData)
case cancelled(provider: String, reference: String?)
case failed(provider: String, reference: String?, error: SanwoError)
}
struct SuccessData {
let provider: String
let reference: String
let transactionId: String?
let raw: Any?
}
sanwo(from: self, options: options) { result in
switch result {
case .successful(let data):
print("Paid! Ref: \(data.reference)")
if let txnId = data.transactionId {
print("Transaction ID: \(txnId)")
}
case .cancelled(let provider, let reference):
print("Cancelled by user (provider: \(provider))")
case .failed(let provider, let reference, let error):
print("Failed: \(error.message)")
}
}
sealed class CheckoutResult {
data class Successful(
val provider: String,
val reference: String,
val transactionId: String? = null,
val raw: Any? = null,
) : CheckoutResult()
data class Cancelled(
val provider: String,
val reference: String? = null,
) : CheckoutResult()
data class Failed(
val provider: String,
val reference: String? = null,
val error: SanwoErrorInfo,
) : CheckoutResult()
}
when (result) {
is CheckoutResult.Successful -> {
Log.d("Sanwo", "Paid! Ref: ${result.reference}")
result.transactionId?.let {
Log.d("Sanwo", "Transaction ID: $it")
}
}
is CheckoutResult.Cancelled -> {
Log.d("Sanwo", "User cancelled")
}
is CheckoutResult.Failed -> {
Log.e("Sanwo", "Failed: ${result.error.message}")
if (result.error.recoverable) {
// safe to retry
}
}
}

Returned inside FailedCheckoutResult (web) and CheckoutResult.Failed (native).

interface SanwoErrorInfo {
code: SanwoErrorCode;
message: string;
provider?: string;
recoverable: boolean;
cause?: unknown;
}
Field Type Description
code SanwoErrorCode Machine-readable error code. See table below.
message string Human-readable error description.
provider string? Provider that raised the error, if applicable.
recoverable boolean true if the checkout can be retried without changes.
cause unknown? The original error/exception from the provider SDK.

All 12 error codes with descriptions:

Code Description
UNKNOWN An unexpected error occurred that does not match any known category.
NETWORK_ERROR Network request failed (timeout, DNS, connectivity).
PROVIDER_ERROR The payment provider returned an error.
INVALID_AMOUNT The amount is invalid (zero, negative, or non-numeric).
INVALID_CURRENCY The currency code is not supported or malformed.
INVALID_CUSTOMER Customer data is missing or invalid (e.g. no email).
INVALID_KEY The public key is invalid, expired, or does not match the provider.
CHECKOUT_TIMEOUT The checkout exceeded the configured timeout duration.
PROVIDER_NOT_FOUND No provider was configured or the provider package is missing.
TEMPLATE_ERROR The provider’s HTML template failed to load or render.
BRIDGE_ERROR Communication between the checkout UI and the host app broke down.
CANCELLED_BY_SYSTEM The checkout was cancelled by the OS or system (e.g. app backgrounded on mobile).