Error Codes
The authoritative source of truth for platform error metadata is the backend catalog in IkawaariErrorCatalog and IkawaariPaaSDomainErrorCodes.
This page documents the implemented error modules, representative codes, HTTP status behavior, and retry guidance.
Canonical error contract
Every HTTP error uses the same envelope. For validation failures, errors is the source of truth; param, reason, and message mirror the first item for existing clients.
{
"error": {
"code": "IKW-REQ-003",
"message": "The mobile money operator is not supported in Côte d’Ivoire.",
"module": "REQ",
"retryable": false,
"param": "destination.mobile_money.operator",
"reason": "unsupported_value",
"errors": [
{
"param": "destination.mobile_money.operator",
"location": "body",
"reason": "unsupported_value",
"message": "Use a supported operator.",
"allowed_values": ["orange_money", "wave", "mtn_momo"]
}
],
"correlation_id": "req_...",
"trace_id": "00-...",
"doc_url": "https://docs.ikawaari.com/docs/error-codes#IKW-REQ-003",
"details": {}
}
}
Branch on code, param, and reason, never on localized message text. details is reserved for non-validation business context.
Reading code, parameter, and reason
codeidentifies the public error family, for exampleIKW-REQ-002for a missing required field.paramidentifies the exact public field to fix: JSON body, query, route, or header.reasonexplains the stable cause:required,invalid_format,unsupported_value,mismatch, and so on.errors[]contains all validation errors; the root mirrors the first item for compatibility.
Missing header example:
{
"error": {
"code": "IKW-REQ-002",
"param": "Idempotency-Key",
"reason": "required",
"errors": [
{"param": "Idempotency-Key", "location": "header", "reason": "required"}
]
}
}
Unsupported routing value example:
{
"error": {
"code": "IKW-REQ-003",
"param": "payment_method",
"reason": "unsupported_value",
"errors": [
{
"param": "payment_method",
"location": "body",
"reason": "unsupported_value",
"allowed_values": ["mobile_money", "card", "pi_uemoa"]
}
]
}
}
Validation reasons
| Reason | Meaning |
|---|---|
required | missing body property, header, query, or path value |
malformed_json | JSON document cannot be parsed |
type_mismatch | JSON type does not match the contract |
unknown_field | property is not declared by the DTO |
invalid_format | invalid format or length |
out_of_range | value is outside its limits |
unsupported_value | well-formed value is not supported |
mutually_exclusive | parameters cannot be used together |
dependency_missing | a dependent parameter is missing |
mismatch | values or contexts are inconsistent |
constraint_violation | another DTO or business constraint failed |
location is body, query, path, or header. Body paths use public snake_case JSON names, such as destination.mobile_money.operator.
JSON and unknown fields
Malformed JSON returns malformed_json. A wrong JSON type returns type_mismatch with the known path. Unknown fields are rejected in sandbox and preproduction with unknown_field; live traffic is observed during the migration window before global rejection is enabled.
See Fixing a validation error for body, query, path, and header examples.
Source-of-truth policy
- Code values come from
IkawaariPaaSDomainErrorCodes - Module, HTTP status, and retryability come from
IkawaariErrorCatalog - Some backward-compatible engine aliases are also mapped in the catalog
HTTP status reference
| Code | Meaning |
|---|---|
200 | Success |
201 | Created |
400 | Bad request or invalid input |
401 | Authentication required or invalid credentials/token |
402 | Balance or funds constraint |
403 | Forbidden, policy blocked, or merchant mismatch |
404 | Resource not found |
409 | State conflict, duplicate operation, or idempotency conflict |
410 | Expired invitation or resource lifecycle ended |
412 | Precondition failed |
423 | Locked or already-active environment/test mode state |
429 | Rate limit or retry cooldown triggered |
500 | Internal platform error |
502 | Upstream provider or webhook delivery failure |
503 | Service temporarily unavailable |
504 | Upstream or system timeout |
Module summary
| Module | Typical area | Typical statuses | Retryable cases |
|---|---|---|---|
AUTH | login, tokens, API keys | 401 | no |
AUTHZ | roles, membership, scopes | 403 | no |
ORG | organization access | 403, 404 | no |
MERCHANT | merchant state and account resolution | 403, 404, 409, 410 | no |
REQ | validation and idempotency | 400, 409 | no |
RES | generic resource state | 404, 409 | concurrent conflicts only |
RATE | throttling | 429 | yes |
SYS | platform/system failures | 500, 503, 504 | some |
CHK | checkout flows | 400, 404 | no |
TRANSFER | payments and refunds | 400, 402, 404, 409, 502 | provider failures only |
PAYOUT | payout operations | 400, 402, 403, 404, 409 | no |
BILLING | invoices and plans | 404, 500 | cycle errors only |
LEDGER | balance and accounting | 400, 402, 404 | no |
COMPLIANCE | KYC, limits | 400, 403 | no |
SECURITY | MFA, passkeys, challenges | 400, 403, 429, 500 | no |
RISK | case handling and rules | 404, 409 | no |
CONFIG | feature flags and country/currency policy | 400, 403 | no |
PRODUCT | product catalog | 400, 404 | no |
WEBHOOK | webhook endpoints and delivery | 404, 502 | delivery failures only |
TERMINAL | reader/session transitions | 400, 409 | no |
EXTERNAL | provider integrations | 400, 502, 504 | unavailable/timeout only |
ESCROW | escrow contracts and disputes | 400, 403, 404, 409 | no |
FUNDING | funding campaigns | 400, 403, 404, 409 | no |
MKTPLACE | marketplace engine | 400, 403 | no |
APP | ecosystem app lifecycle | 403, 404 | no |
ENV | sandbox/live test-mode state | 412, 423 | no |
CONNECT | connected account configuration | 400, 404 | no |
Authentication and authorization
| Code | Module | HTTP | Retryable | Meaning |
|---|---|---|---|---|
IKW-AUTH-001 | AUTH | 401 | No | Invalid credentials |
IKW-AUTH-002 | AUTH | 401 | No | Authentication required |
IKW-AUTH-003 | AUTH | 401 | No | Token revoked |
IKW-AUTH-004 | AUTH | 401 | No | Token expired |
IKW-AUTH-005 | AUTH | 401 | No | Token invalid |
IKW-AUTH-006 | AUTH | 401 | No | Session expired |
IKW-AUTH-007 | AUTH | 401 | No | Session revoked |
IKW-AUTH-008 | AUTH | 401 | No | API key expired |
IKW-AUTH-009 | AUTH | 401 | No | API key rotated |
IKW-AUTHZ-001 | AUTHZ | 403 | No | Forbidden |
IKW-AUTHZ-002 | AUTHZ | 403 | No | Insufficient role |
IKW-AUTHZ-003 | AUTHZ | 403 | No | Membership required |
Merchant, request, and system foundations
| Code | Module | HTTP | Retryable | Meaning |
|---|---|---|---|---|
IKW-MERCHANT-001 | MERCHANT | 404 | No | Merchant not found |
IKW-MERCHANT-002 | MERCHANT | 403 | No | Merchant disabled |
IKW-MERCHANT-003 | MERCHANT | 409 | No | Merchant already exists |
IKW-MERCHANT-004 | MERCHANT | 410 | No | Merchant invitation expired |
IKW-MERCHANT-005 | MERCHANT | 404 | No | Merchant account not found |
IKW-REQ-001 | REQ | 400 | No | Invalid input |
IKW-REQ-002 | REQ | 400 | No | Required parameter missing |
IKW-REQ-003 | REQ | 400 | No | Parameter invalid |
IKW-REQ-004 | REQ | 409 | No | Idempotency conflict |
idempotency_key_conflict | REQ | 409 | No | Backward-compatible idempotency conflict alias |
IKW-RES-001 | RES | 404 | No | Resource not found |
IKW-RES-002 | RES | 409 | No | Resource already exists |
IKW-RES-003 | RES | 409 | No* | Resource state conflict |
IKW-RATE-001 | RATE | 429 | Yes | Too many requests |
IKW-SYS-001 | SYS | 500 | No | Internal error |
IKW-SYS-002 | SYS | 503 | Yes | Service unavailable |
IKW-SYS-003 | SYS | 504 | Yes | System timeout |
IKW-RES-003 is usually not retryable when it reports an impossible state transition. It becomes retryable when the message indicates a transient concurrency conflict, for example Payment intent confirmation is already in progress. or The resource was modified concurrently. Please retry the operation.
Checkout, payments, refunds, and payouts
| Code | Module | HTTP | Retryable | Meaning |
|---|---|---|---|---|
IKW-CHK-001 | CHK | 400 | No | Invalid payment link |
IKW-CHK-002 | CHK | 404 | No | Checkout session not found |
IKW-CHK-003 | CHK | 400 | No | Checkout session expired |
IKW-CHK-004 | CHK | 400 | No | Checkout session not open |
IKW-CHK-005 | CHK | 400 | No | Checkout amount required |
IKW-CHK-006 | CHK | 400 | No | Checkout has no payment intent |
IKW-CHK-007 | CHK | 400 | No | Receipt not available |
IKW-TRANSFER-001 | TRANSFER | 400 | No | Invalid amount |
IKW-TRANSFER-002 | TRANSFER | 400 | No | Currency mismatch |
IKW-TRANSFER-003 | TRANSFER | 404 | No | Transfer or payment not found |
IKW-TRANSFER-004 | TRANSFER | 409 | No | Invalid state transition |
IKW-TRANSFER-005 | TRANSFER | 400 | No | Refund exceeds amount |
IKW-TRANSFER-006 | TRANSFER | 409 | No | Already refunded |
IKW-TRANSFER-007 | TRANSFER | 502 | Yes | Provider failed |
IKW-TRANSFER-008 | TRANSFER | 402 | No | Insufficient balance |
IKW-PAYOUT-001 | PAYOUT | 404 | No | Payout not found |
IKW-PAYOUT-002 | PAYOUT | 400 | No | Invalid destination |
IKW-PAYOUT-003 | PAYOUT | 402 | No | Insufficient payout balance |
IKW-PAYOUT-004 | PAYOUT | 409 | No | Batch already processing |
IKW-PAYOUT-005 | PAYOUT | 409 | No | Batch already completed |
IKW-PAYOUT-006 | PAYOUT | 400 | No | Invalid recipient |
IKW-PAYOUT-007 | PAYOUT | 403 | No | AML rejected |
IKW-PAYOUT-008 | PAYOUT | 403 | No | Merchant mismatch |
IKW-PAYOUT-009 | PAYOUT | 400 | No | Currency mismatch |
Billing, ledger, products, and configuration
| Code | Module | HTTP | Retryable | Meaning |
|---|---|---|---|---|
IKW-BILLING-001 | BILLING | 404 | No | Invoice not found |
IKW-BILLING-002 | BILLING | 404 | No | Plan not found |
IKW-BILLING-003 | BILLING | 500 | Yes | Billing cycle error |
IKW-LEDGER-001 | LEDGER | 404 | No | Ledger account not found |
IKW-LEDGER-002 | LEDGER | 402 | No | Insufficient balance |
IKW-LEDGER-003 | LEDGER | 400 | No | Currency mismatch |
IKW-CONFIG-001 | CONFIG | 403 | No | Feature disabled |
IKW-CONFIG-002 | CONFIG | 400 | No | Country/currency disabled |
IKW-PRODUCT-001 | PRODUCT | 404 | No | Product not found |
IKW-PRODUCT-002 | PRODUCT | 400 | No | Invalid product name |
IKW-PRODUCT-003 | PRODUCT | 400 | No | Invalid product price |
Security, compliance, risk, webhook, and external providers
| Code | Module | HTTP | Retryable | Meaning |
|---|---|---|---|---|
IKW-COMPLIANCE-001 | COMPLIANCE | 403 | No | KYC required |
IKW-COMPLIANCE-002 | COMPLIANCE | 400 | No | Compliance document expired |
IKW-COMPLIANCE-003 | COMPLIANCE | 403 | No | Compliance limit exceeded |
IKW-SECURITY-001 | SECURITY | 403 | No | MFA required |
IKW-SECURITY-002 | SECURITY | 400 | No | Invalid MFA code |
IKW-SECURITY-003 | SECURITY | 429 | No | Too many MFA attempts |
IKW-SECURITY-004 | SECURITY | 400 | No | Invalid passkey |
IKW-SECURITY-005 | SECURITY | 400 | No | Google OAuth failed |
IKW-SECURITY-006 | SECURITY | 409 | No | Google already linked |
IKW-SECURITY-007 | SECURITY | 429 | No | Security cooldown active |
IKW-SECURITY-008 | SECURITY | 500 | No | Google not configured |
IKW-SECURITY-009 | SECURITY | 400 | No | Google email not verified |
IKW-SECURITY-010 | SECURITY | 400 | No | Challenge expired |
IKW-SECURITY-011 | SECURITY | 400 | No | Challenge not verified |
IKW-SECURITY-012 | SECURITY | 400 | No | Challenge mismatch |
IKW-RISK-001 | RISK | 409 | No | Risk case already decided |
IKW-RISK-002 | RISK | 404 | No | Risk rule not found |
IKW-RISK-003 | RISK | 409 | No | Risk case cannot assign |
IKW-WEBHOOK-001 | WEBHOOK | 404 | No | Webhook endpoint not found |
IKW-WEBHOOK-002 | WEBHOOK | 502 | Yes | Webhook delivery failed |
IKW-EXTERNAL-001 | EXTERNAL | 502 | Yes | Provider unavailable |
IKW-EXTERNAL-002 | EXTERNAL | 504 | Yes | Provider timeout |
IKW-EXTERNAL-003 | EXTERNAL | 400 | No | Provider rejected request |
Escrow, funding, marketplace, apps, environment, and connect
| Code | Module | HTTP | Retryable | Meaning |
|---|---|---|---|---|
IKW-ESCROW-001 | ESCROW | 404 | No | Escrow contract not found |
IKW-ESCROW-002 | ESCROW | 409 | No | Invalid escrow transition |
IKW-ESCROW-003 | ESCROW | 409 | No | Active dispute blocks operation |
IKW-ESCROW-004 | ESCROW | 400 | No | Escrow currency mismatch |
IKW-ESCROW-005 | ESCROW | 403 | No | Escrow merchant mismatch |
IKW-ESCROW-006 | ESCROW | 403 | No | Escrow feature disabled |
IKW-ESCROW-007 | ESCROW | 409 | No | Duplicate escrow operation |
IKW-FUNDING-001 | FUNDING | 404 | No | Funding campaign not found |
IKW-FUNDING-002 | FUNDING | 409 | No | Invalid funding transition |
IKW-FUNDING-003 | FUNDING | 400 | No | Insufficient amount |
IKW-FUNDING-004 | FUNDING | 400 | No | Funding currency mismatch |
IKW-FUNDING-005 | FUNDING | 403 | No | Funding merchant mismatch |
IKW-FUNDING-006 | FUNDING | 403 | No | Funding feature disabled |
IKW-FUNDING-007 | FUNDING | 409 | No | Duplicate contribution |
IKW-MKTPLACE-001 | MKTPLACE | 403 | No | Seller suspended |
IKW-MKTPLACE-002 | MKTPLACE | 400 | No | Invalid marketplace order |
IKW-MKTPLACE-003 | MKTPLACE | 400 | No | Commission error |
IKW-MKTPLACE-004 | MKTPLACE | 400 | No | Marketplace currency mismatch |
IKW-MKTPLACE-005 | MKTPLACE | 403 | No | Marketplace merchant mismatch |
IKW-MKTPLACE-006 | MKTPLACE | 400 | No | Marketplace refund not allowed |
IKW-APP-001 | APP | 404 | No | App not found |
IKW-APP-002 | APP | 403 | No | App kill switch enabled |
IKW-APP-003 | APP | 403 | No | Installation inactive |
IKW-ENV-001 | ENV | 412 | No | Test mode not activated |
IKW-ENV-002 | ENV | 423 | No | Test mode already active |
IKW-CONNECT-001 | CONNECT | 404 | No | Connected account not found |
IKW-CONNECT-002 | CONNECT | 400 | No | Invalid connected account configuration |
Backward-compatible engine aliases
The catalog also maps legacy engine error strings to canonical platform codes.
Examples include:
PayoutEngine:BatchNotFound→IKW-PAYOUT-001EscrowEngine:ContractNotFound→IKW-ESCROW-001FundingEngine:CampaignNotFound→IKW-FUNDING-001MarketplaceEngine:SellerSuspended→IKW-MKTPLACE-001
How to handle errors
- Use the
codeas the programmatic key for branching logic. - Use
errorsto display every form or payload error. - Use
paramandreasonto attach an error to its field. - Use
HTTP statusfor transport-level behavior. - Only retry when the catalog marks the condition as effectively retryable, such as rate limits, provider unavailability, or timeouts.
- For merchant-scoped flows, prefer surfacing user-action guidance rather than raw internal implementation terms.