Error catalogue
Every error response from the gateway uses the
PaymentGatewayError envelope with a stable
four-digit error_code. This page is the full catalogue. Branch on
error_code, never on message.
The leading digit groups the cause:
- 10xx — Authentication
- 11xx — Validation
- 12xx — Business logic
- 13xx — Security
- 14xx — System
- 15xx — Payment processor
10xx Authentication
Section titled “10xx Authentication”Issues with credentials. Never auto-retry — these need human intervention or a fresh credential.
| Code | Symbol | Cause | Fix |
|---|---|---|---|
1001 | INVALID_APP_KEY | The merchant_secret or session_token is unknown, expired, or revoked. | Mint a fresh session for session_token. Rotate the key for merchant_secret. |
1002 | APP_KEY_MISSING | No Authorization header was sent. | Add the Authorization: Bearer … header. |
1003 | APP_NOT_ALLOWED | The key is valid but the caller isn’t on the allow-list (IP CIDR mismatch). | Add the source IP to the merchant key’s allow-list, or call from an allowed network. |
1004 | APP_SUSPENDED | The merchant account is suspended. | Contact your Pdirect rep. Do not retry. |
1005 | APP_EXPIRED | The credential’s hard expiry passed. | Rotate the key. |
11xx Validation
Section titled “11xx Validation”Bad request shape or content. Fix on your side and don’t retry the same payload.
| Code | Symbol | Cause | Fix |
|---|---|---|---|
1101 | INVALID_AMOUNT | amount is <= 0, malformed, or doesn’t match session binding. | Validate before sending. If session binding mismatch, mint a new session. |
1102 | INVALID_CURRENCY | currency not in [usd, cdf, xof] or doesn’t match session binding. | Use lowercase ISO 4217. Mint a new session if the session binding is the issue. |
1103 | INVALID_PAYMENT_METHOD | payment_method not in the supported set. | Check against Payment methods. |
1104 | INVALID_PHONE_NUMBER | phone_number doesn’t match ^\+?\d{1,15}$. | Format as E.164 (+CCNNNNN…). |
1105 | INVALID_EMAIL | Email regex failure. | Validate client-side. |
1106 | INVALID_CARD_NUMBER | Card fails Luhn check or length is out of [13, 19]. | Validate client-side. |
1107 | INVALID_CARD_EXPIRY | Expiry date format is wrong or in the past. | Use MM/YY or MM/YYYY per the field; validate. |
1108 | INVALID_CARD_CVV | CVV not 3 or 4 digits. | Validate client-side. |
1109 | MISSING_REQUIRED_FIELD | A required field for the chosen payment_method is missing. | See Payment methods for the conditional table. |
1110 | INVALID_FIELD_FORMAT | Generic Pydantic validation failure. The details array has field-level breakdown. | Read details, fix the field. |
12xx Business logic
Section titled “12xx Business logic”The request was well-formed but the business state forbids it.
| Code | Symbol | Cause | Fix |
|---|---|---|---|
1201 | INSUFFICIENT_FUNDS | Customer can’t pay the requested amount. | Surface to customer. Don’t auto-retry. |
1202 | TRANSACTION_LIMIT_EXCEEDED | Per-customer or per-merchant transaction cap hit. | Surface to customer; contact your rep if the limit is wrong. |
1203 | DUPLICATE_TRANSACTION | Same payment already processed (idempotency reuse with no replay match). | Use the original transaction_id. |
1204 | TRANSACTION_NOT_FOUND | The transaction_id or payment_id doesn’t exist or isn’t visible to this caller. | Check the ID, check session ownership. |
1205 | PAYMENT_METHOD_NOT_SUPPORTED | The chosen method isn’t enabled for this merchant or country. | Use a supported method or have your rep enable it. |
1206 | CURRENCY_NOT_SUPPORTED | The currency isn’t enabled for this method. | Switch method or currency. |
1207 | BENEFICIARY_LIMIT_EXCEEDED | More than 100 beneficiaries on /payments/send. | Split into multiple calls. |
13xx Security
Section titled “13xx Security”Rate limiting, blocked IPs, signature failures.
| Code | Symbol | Cause | Fix |
|---|---|---|---|
1301 | RATE_LIMIT_EXCEEDED | Per-bucket limit exceeded. | Honour Retry-After. See Rate limits. |
1302 | SUSPICIOUS_ACTIVITY | Risk engine flagged the request. | Surface a generic error to the customer; investigate. |
1303 | IP_BLOCKED | Source IP on a deny-list. | Use a different network or appeal to ops. |
1304 | INVALID_SIGNATURE | Mastercard 3DS callback signature mismatch (or webhook signature when that ships). | Misconfigured MASTERCARD_WEBHOOK_SECRET on the gateway side; not normally your problem. |
1305 | REQUEST_TOO_LARGE | Request body over the 1MB limit. | Reduce payload size. |
14xx System
Section titled “14xx System”Gateway-side or infrastructure problems. Often retryable: true.
| Code | Symbol | Cause | Fix |
|---|---|---|---|
1401 | INTERNAL_SERVER_ERROR | Unhandled gateway exception. | Quote the request_id to support. Retry with Idempotency-Key if retryable: true. |
1402 | SERVICE_UNAVAILABLE | A downstream is offline; gateway can’t process. | Retry with backoff. |
1403 | DATABASE_ERROR | Persistence-layer failure. | Quote the request_id. Retry with backoff. |
1404 | EXTERNAL_SERVICE_ERROR | A processor (Mastercard, Onafriq, etc.) is misbehaving. | Retry with backoff. |
1405 | CONFIGURATION_ERROR | Merchant configuration is incomplete (e.g. notify_url allow-list empty when the SDK sent a notify_url). | Fix configuration in the dashboard; do not auto-retry. |
15xx Payment processor
Section titled “15xx Payment processor”The processor said no.
| Code | Symbol | Cause | Fix |
|---|---|---|---|
1501 | PAYMENT_PROCESSOR_ERROR | Generic processor-side failure. | Read failure_reason if present; surface or retry per retryable. |
1502 | PAYMENT_DECLINED | Issuer or processor declined the transaction. | Don’t auto-retry from the same source. Surface to the customer. |
1503 | PAYMENT_TIMEOUT | Processor didn’t respond in time. | Retry with Idempotency-Key to avoid double-charging. |
1504 | PAYMENT_CANCELLED | Customer or system cancelled mid-flight. | Don’t retry; treat as a fresh start. |
1505 | WEBHOOK_DELIVERY_FAILED | Outbound webhook to your notify_url failed all retries. | Check your endpoint health. The transaction is still in its real state — query /payments/status/{id}. |
SDK summary classification
Section titled “SDK summary classification”Both SDKs collapse the four-digit codes into a nine-state
PdirectPayApiResponseCode enum (LOK000–LOK009) for UI display.
See the mapping in
Flutter error handling or
Angular error handling.
When you need the exact gateway code, drop down to the underlying
HTTP client (PdirectHttpClient / PdirectHttpClientService) and
read the response body’s error_code field.
See also
Section titled “See also”- Errors — the envelope shape and SDK mapping
- Rate limits —
1301in context - Idempotency — safe retry for
1401/1503