Errors
HTTP codes, errors field structure and client-side error handling strategy.
Wajub uses conventional HTTP codes. In summary: 2xx success, 4xx client-side error
(missing parameter, failure, insufficient permissions), 5xx Wajub-side error (rare).
HTTP codes
| Code | Meaning |
|---|---|
200 | Success. |
201 | Resource created (payment/transfer initialized). |
202 | Accepted, asynchronous processing in progress. |
400 | Malformed request. |
401 | Invalid authentication (API key). |
403 | Insufficient permissions on a restricted key, or an IP not on the key's allow-list. |
404 | Resource not found. |
406 | A private/restricted key is required but a public key was used. |
422 | Validation failed — see errors. Also returned when an Idempotency-Key is reused with a different request body (on POST /payments only today; the errors.idempotency_key field explains the conflict). |
429 | Too many requests (rate limit). |
500 | Internal error. |
Error structure
status is always a human-readable HTTP reason phrase (Unprocessable Content, Not Found, Too Many Requests…), never the literal string "error".
{
"status": "Unprocessable Content",
"message": "Some fields are invalid",
"code": 422,
"errors": {
"amount": ["The amount must be at least 100."],
"customer.email": ["The customer.email must be a valid email address."]
}
}messagestringoptionalGlobal message, safe to log.
codeintegeroptionalDuplicated HTTP code.
errorsobjectoptionalPresent on 422. Field → message list map. Nested fields use dot notation.
Handling errors properly
Error handling
try {
const res = await wajub.payments.initialize(params);
} catch (err) {
if (err.code === 422) {
// Per-field validation errors
showFieldErrors(err.errors);
} else if (err.code === 429) {
await sleep(err.retryAfter * 1000); // back-off
} else {
reportToSentry(err);
}
}Inspect an error after the fact
Any request in error remains viewable in Konsole → API Logs: you'll see the sent body, the exact response and the provider involved.