Skip to content

Errors

Every 4xx and 5xx response from the gateway uses the same JSON envelope. Use the error_code for programmatic handling — it’s stable across releases. The HTTP status indicates the broad category; the error_code pinpoints the cause.

{
"error": true,
"error_code": "1101",
"message": "Invalid payment amount",
"details": [
{
"field": "amount",
"message": "Amount must be greater than 0",
"code": "AMOUNT_TOO_SMALL"
}
],
"timestamp": "2026-05-05T10:15:00Z",
"request_id": "req_8f3a4c2e9b1d7a6f",
"support_reference": "sup_987654321",
"transaction_id": "txn_8f3a4c2e9b1d7a6f5c0e8d",
"retryable": false,
"retry_after": null,
"documentation_url": "https://docs.pdirect.com/errors/1101"
}
FieldTypeNotes
errorboolAlways true for error envelopes — easy guard for if (body.error) { ... }.
error_codestringThe four-digit, stable code. Branch on this.
messagestringHuman-readable, localised by Accept-Language. Show to support, not end users.
detailsarray | nullField-level breakdown for 1110 validation errors.
timestampISO 8601Server time the error was generated.
request_idstring | nullEchoes the request — quote it when contacting support.
support_referencestring | nullInternal correlation ID shared with the support team.
transaction_idstring | nullPresent when the error relates to a known transaction.
retryablebooltrue only for transient failures. Never auto-retry on false.
retry_afterint | nullSeconds to wait before retrying when retryable: true.
documentation_urlstring | nullDeep link into this site for the specific code.

The leading digit groups the cause:

RangeGroupExample codes
10011005Authentication1001 INVALID_APP_KEY, 1004 APP_SUSPENDED
11011110Request validation1101 INVALID_AMOUNT, 1106 INVALID_CARD_NUMBER, 1109 MISSING_REQUIRED_FIELD
12011207Business logic1201 INSUFFICIENT_FUNDS, 1203 DUPLICATE_TRANSACTION
13011305Security & rate-limiting1301 RATE_LIMIT_EXCEEDED, 1304 INVALID_SIGNATURE
14011405Server / system1401 INTERNAL_SERVER_ERROR, 1402 SERVICE_UNAVAILABLE
15011505Payment processor1502 PAYMENT_DECLINED, 1503 PAYMENT_TIMEOUT

The full catalogue with remediation is at Errors → catalogue.

Always branch on the code, not the message — messages are translated and may change for clarity.

function handlePdirectError(body: { error_code: string; message: string; retryable: boolean }) {
switch (body.error_code) {
case "1001": // INVALID_APP_KEY
case "1004": // APP_SUSPENDED
// Stop. Don't retry. Surface to operations.
throw new AuthenticationFailed(body.message);
case "1101": // INVALID_AMOUNT
case "1102": // INVALID_CURRENCY
// Body drifted from session binding. Mint a new session.
throw new SessionDriftError(body.message);
case "1301": // RATE_LIMIT_EXCEEDED
// Honour retry_after if present.
throw new RateLimited(body.retry_after ?? 60);
case "1402": // SERVICE_UNAVAILABLE
case "1502": // PAYMENT_DECLINED — note: not retryable from same source
case "1503": // PAYMENT_TIMEOUT
if (body.retryable) {
return scheduleRetry(body);
}
throw new ProcessorFailure(body.message);
default:
throw new UnknownGatewayError(body.error_code, body.message);
}
}
  • Never auto-retry on retryable: false. Doing so on an authentication or validation error wastes attempts and can trip rate limits.
  • Use Idempotency-Key for any retry. The gateway will replay the cached response if the same (key, body_hash) arrives within 24 h, and return 409 if the body changed. See Idempotency.
  • Honour retry_after on 429. The header Retry-After: <seconds> is also set.

Both SDKs surface a typed error object. The string errorCode field mirrors the gateway’s error_code (note: SDKs use the LOK000LOK009 summary classification; the underlying gateway code is on the same response).

// Flutter
PdirectPayCheckout(
// ...
onError: (PdirectPayOnError e) {
print('${e.errorCode} ${e.message}');
// e.errorCode is one of LOK000..LOK009 (summary codes)
},
);
// Angular
onError(e: PdirectPayOnError) {
console.warn(e.errorCode, e.message);
// e.errorCode is PdirectPayApiResponseCode (LOK000..LOK009)
}

When you need the underlying four-digit gateway code, read it off the HTTP response when calling endpoints directly via PdirectHttpClient. The widget-level callbacks deliberately abstract to the simpler nine-state classification for UI display.