Flutter — error handling
The drop-in widget surfaces errors through a single onError
callback. Direct service calls return a PdirectHttpResponse<T>
wrapper you check explicitly. Both paths funnel into the same
PdirectPayApiResponseCode enum.
Widget-level
Section titled “Widget-level”PdirectPayCheckout( configs: configs, paymentBody: paymentBody, onResponse: (r) { // success path: r.paymentStatus == PdirectPaymentStatus.approved }, onError: (PdirectPayOnError e) { debugPrint('${e.errorCode?.name} ${e.message}'); switch (e.errorCode) { case PdirectPayApiResponseCode.lok003: // auth failed _logoutAndRedirect(); break; case PdirectPayApiResponseCode.lok005: // insufficient funds _showSimpleError(e.message); break; case PdirectPayApiResponseCode.lok008: // timeout _showRetryPrompt(e.message); break; default: _showSimpleError(e.message); } },)PdirectPayOnError fields:
| Field | Notes |
|---|---|
message | Localised, human-readable. Don’t surface to end users; show your own copy. |
title | Localised display title. |
errorCode | PdirectPayApiResponseCode? — LOK000–LOK009. |
identifier | Optional gateway-side identifier. |
customerReference | Echoed from the request. |
systemReference | Gateway transaction id, if any. |
amount, currency | Echoed from the request. |
successRedirectUrl, failRedirectUrl | Echoed. |
timestamp | Defaults to DateTime.now() when unset. |
Service-level
Section titled “Service-level”PdirectHttpClient returns PdirectHttpResponse<T> — never throws
on HTTP errors. Check isSuccess and inspect error for the
underlying DioException.
final result = await PdirectHttpClient.instance.post<Map<String, dynamic>>( '/payments/collect', data: paymentBody.toJson(),);
if (!result.isSuccess) { final code = result.statusCode; final body = result.data; // gateway error envelope final dioError = result.error; // raw exception, if any // body['error_code'] is the underlying four-digit code.}When you call PdirectPaymentService methods, you get the same
wrapper.
Mapping the summary code to gateway codes
Section titled “Mapping the summary code to gateway codes”The widget’s PdirectPayApiResponseCode (LOK000–LOK009)
collapses the gateway’s four-digit ranges into nine display
buckets. If you need the exact gateway code, drop down to
PdirectHttpClient and parse the response body’s error_code field.
PdirectPayApiResponseCode | Typical gateway codes |
|---|---|
lok000 Success | (no error) |
lok001 General error | 1401, 1403 |
lok002 Invalid params | 1101–1110 |
lok003 Auth failed | 1001–1005 |
lok004 Method unavailable | 1205, 1206 |
lok005 Insufficient funds | 1201, 1202 |
lok006 Limit exceeded | 1207, 1301 (rate limit) |
lok007 Network error | (client-side classification) |
lok008 Timeout | 1503 |
lok009 Service unavailable | 1402, 1404 |
See the full Error catalogue for every gateway code.
Common errors and what to do
Section titled “Common errors and what to do”Session-binding mismatch (lok002, gateway 1101 / 1102 / 1103)
Section titled “Session-binding mismatch (lok002, gateway 1101 / 1102 / 1103)”The body’s amount, currency, or customer_reference doesn’t
match the values your backend declared at session-mint. Auth-v3
makes those three fields optional in PdirectPaymentBody — if
you leave them unset, the SDK omits them on the wire and the gateway
reads the bound values straight from the session, sidestepping this
class of failure entirely.
Fix: drop the three fields from PdirectPaymentBody (or mint a
fresh session whose bound values match what you intend to send).
Don’t try to “correct” the body on retry — the gateway will reject.
Session expired or consumed (lok003, gateway 1001)
Section titled “Session expired or consumed (lok003, gateway 1001)”The session’s TTL ran out, or /payments/submit already succeeded
once on this session.
Fix: mint a new session. Sessions are single-use.
Device fingerprint mismatch (lok003, gateway 1001)
Section titled “Device fingerprint mismatch (lok003, gateway 1001)”The session was first used from a different device than this one.
Fix: mint a new session from this device. This usually only shows up in development if you re-use a token across emulators.
OTP rate limited (lok006, gateway 1301)
Section titled “OTP rate limited (lok006, gateway 1301)”Five OTP attempts in five minutes. The customer has miskeyed too many times or your client is auto-retrying.
Fix: show a “wait and try again” UX, honour retry_after.
Insufficient funds (lok005, gateway 1201)
Section titled “Insufficient funds (lok005, gateway 1201)”The customer doesn’t have enough money in their wallet / mobile money account / card limit.
Fix: non-recoverable from the gateway side. Surface to the customer.
Logging
Section titled “Logging”The SDK never logs request bodies. Card data, PINs, OTP codes, and
session tokens are filtered out of every log path. Your logger
callback (set on PdirectPayConfig.logger) only ever sees safe
strings.
PdirectPay.init(PdirectPayConfig( environment: PdirectPayEnvironment.production, logger: (msg) { // safe to forward to Sentry, Datadog, etc. Sentry.addBreadcrumb(Breadcrumb(message: msg, category: 'pdirect')); },));See also
Section titled “See also”- Errors — the full envelope and code groups
- Errors → catalogue — every gateway code with remediation
- API reference