API Reference
Session & State
PaymentSession is the canonical record. PaymentState enumerates every legal moment in a checkout.
PaymentSession
The single source of truth passed between every layer. Immutable; mutate via copyWith.
class PaymentSession {
final String paymentId;
final String invoiceId;
final String merchantId;
final int amountMinor;
final String currency;
final PaymentState state;
final PaymentMethod? method; // qr | account
final String? qrPayload; // data URL or qrCode string
final String? statusMessage;
final DateTime? expiresAt;
// Customer / wallet metadata, populated as the flow progresses
final String? customerName;
final String? customerPhone;
final String? walletAccountId;
final String? institutionName;
// Terminal-state fields, populated on success
final String? transactionId;
final String? referenceId;
final String? dphReference;
final String? receiverName;
final String? receiverAccountNumber;
final DateTime? completedAt;
final String? remarks;
final int version;
bool get isTerminal =>
state == PaymentState.success ||
state == PaymentState.failed ||
state == PaymentState.expired;
}
PaymentState
enum PaymentState {
created, // session exists, no flow chosen
pending, // initiate returned, not yet showing UI
qrGenerated, // QR is on screen, waiting for scan
waitingPayment, // backend is processing (post-OTP for OnePay)
otpRequired, // OTP screen visible
authorized, // OTP accepted, settlement pending
success, // terminal — money moved
failed, // terminal — declined / rejected
expired, // terminal — session timed out
}
Allowed transitions
PaymentStateMachine enforces this table. Self-transitions are always allowed.
| From | To |
|---|---|
created |
pending, failed, expired |
pending |
qrGenerated, waitingPayment, otpRequired, failed, expired |
qrGenerated |
waitingPayment, otpRequired, success (fast-path), failed, expired |
waitingPayment |
otpRequired, authorized, success, failed, expired |
otpRequired |
authorized, success (fast-path), failed, expired |
authorized |
success, failed |
success |
— (terminal) |
failed |
— (terminal) |
expired |
— (terminal) |
Two non-obvious "fast-path" edges exist for backends that collapse intermediate states:
qrGenerated → success— webhook fires before the gateway pollswaitingPayment.otpRequired → success— backend settles immediately after OTP.
Illegal transitions throw PaymentStateTransitionException.
PaymentMethod
enum PaymentMethod { qr, account }
account covers both OnePay bank accounts and PayNow wallets — the difference is the institutionCode on ValidateAccountRequest.
Currency helpers
The paynow_core/payment_models.dart library exposes:
int currencyFractionDigits(String currency)— handles 3-digit currencies (LYD/BHD/KWD/OMR/TND), 0-digit (JPY/KRW), and the 2-digit default.String formatCurrencyAmount(int amountMinor, String currency)— returnsLYD 25.900etc., with thousand separators.
PaymentEvent
class PaymentEvent {
final String paymentId;
final PaymentSession? previousSession;
final PaymentSession currentSession;
final DateTime occurredAt;
}
Emitted by PaymentEngine on every successful API call and every state transition. Subscribe via engine.events or sdk.sessionStream.