Errors#
HTTP status codes#
| Code | Meaning |
|---|
200 OK | Request succeeded |
400 Bad Request | Invalid request body - missing required field or validation failure |
401 Unauthorized | Missing or invalid Bearer token |
403 Forbidden | Token valid but action not permitted (e.g. password expired) |
500 Internal Server Error | Unexpected server error - retry with backoff |
All errors return a consistent JSON body:{
"status": "error",
"isSuccess": false,
"message": "Payment could not be processed due to invalid PSP credentials.",
"errorCode": "INVALID_PSP_CREDENTIALS",
"transactionId": "64a1f2b3c4d5e6f7a8b9c0d1",
"errors": [],
"data": {}
}
| Field | Type | Description |
|---|
status | string | Always "error" for error responses |
isSuccess | boolean | Always false for error responses |
message | string | Friendly human-readable description - safe to display to end users |
errorCode | string | Normalized Mozarto error code - use this for programmatic handling. See Normalized error codes below |
transactionId | string | Mozarto transaction ID - present when a transaction was created before the error occurred |
errors | array | List of specific validation messages (may be empty) |
data | object/null | Raw PSP response payload - kept for backward compatibility. Structure varies by provider |
errorCode is the stable integration point. message is a friendly English string. data contains the raw PSP fields and is kept for backward compatibility - use errorCode for branching logic.
Normalized error codes#
Mozarto maps every PSP error to a canonical errorCode value. Use errorCode for programmatic handling rather than parsing message strings or data.* raw fields.Credentials and configuration#
errorCode | When |
|---|
INVALID_PSP_CREDENTIALS | API key is wrong, missing, or the PSP account is suspended |
PSP_NOT_CONFIGURED | Payment provider is not configured for your brand in the back office |
PSP_ENDPOINT_NOT_FOUND | PSP endpoint returned 404 - check your API credentials configuration |
Payment failures#
errorCode | When |
|---|
CARD_DECLINED | Card was declined by the issuer |
CARD_EXPIRED | Card has expired |
INSUFFICIENT_FUNDS | Card or account has insufficient funds |
THREE_DS_REQUIRED | 3D Secure authentication is required |
THREE_DS_FAILED | 3D Secure authentication failed |
Limits and validation#
errorCode | When |
|---|
AMOUNT_BELOW_MIN | Transaction amount is below the provider minimum |
AMOUNT_ABOVE_MAX | Transaction amount exceeds the provider maximum |
CURRENCY_NOT_SUPPORTED | Currency is not supported by the payment provider |
COUNTRY_NOT_SUPPORTED | Country is not supported by the payment provider |
DUPLICATE_TRANSACTION | A duplicate transaction was detected |
Orchestration#
errorCode | When |
|---|
ORCHESTRATION_RULE_NOT_MATCHED | No active orchestration rule matches the request |
ORCHESTRATION_CONDITION_FAILED | A matching rule exists but the request fails its conditions (e.g. amount out of range) |
Connectivity#
errorCode | When |
|---|
PSP_TIMEOUT | PSP did not respond in time - safe to retry |
PSP_UNAVAILABLE | PSP returned a 5xx error - safe to retry with backoff |
PSP_RATE_LIMITED | Too many requests to the PSP - retry after a delay |
Fallback#
errorCode | When |
|---|
UNKNOWN_PSP_ERROR | PSP returned an unrecognised response - contact support if it persists |
INTERNAL_ERROR | Unexpected Mozarto-side error |
Retryability#
| Retryable | Error codes |
|---|
| Yes - retry with backoff | PSP_TIMEOUT, PSP_UNAVAILABLE, PSP_RATE_LIMITED |
| No - fix the request or configuration | All other codes |
Common errors#
Missing required field - 400#
{
"status": "error",
"message": "Missing required field: pspType",
"isSuccess": false,
"errors": []
}
Validation failed - 400#
{
"status": "error",
"message": "Validation failed",
"isSuccess": false,
"errors": [
"amount must not be empty",
"email must be a valid email"
]
}
Invalid token - 401#
{
"status": "error",
"message": "Unauthorized",
"isSuccess": false,
"errors": []
}
Verify the Bearer token is present and has not expired.{
"status": "error",
"message": "Rules action is not matched",
"isSuccess": false,
"errors": []
}
No active Orchestration rule exists for your brand and the selected PSP. Go to Orchestration in the back office, create a rule that matches your brand and the pspType you are using, and ensure the rule is active before retrying.Orchestration rule condition not met - 400#
{
"status": "error",
"message": "Error",
"isSuccess": false,
"errors": [
"Amount should be greater than 100. Current value is 11."
]
}
A matching Orchestration rule exists but the request does not satisfy its conditions - for example, the transaction amount is outside the configured min/max range. The errors array contains the specific constraint that failed. Adjust the request to meet the rule's conditions, or update the rule in the back office under Orchestration.PSP configuration not found - 400#
{
"status": "error",
"message": "Something went wrong",
"isSuccess": false,
"data": "PSP Configuration not found. Please check you psp Configuration"
}
The payment provider is not configured for your brand in the Mozarto back office. Go to Payment Methods - Configuration, select the provider, and save the required credentials (username, password, webhook URL, and any provider-specific fields) under your brand before retrying.Provider returned an error - 400#
{
"status": "error",
"message": "Payment provider rejected the request",
"isSuccess": false,
"errors": ["Invalid currency for selected provider"]
}
The request reached the payment provider but was rejected. Check the errors array for the provider's reason.
PSP-specific error responses#
Each provider returns rejection details in a different shape inside the data field. PayOne returns a normalized errorCode at the top level. Worldpay, ForumPay, and Gigadat will include errorCode once migrated to the normalized error format - see Normalized error codes for the full code list.Worldpay#
Worldpay errors return a numeric errorCode and a human-readable errorMessage in data:{
"status": "error",
"message": "Something went wrong",
"isSuccess": false,
"data": {
"errorCode": "5",
"errorMessage": "Invalid card details",
"transactionId": "64a1f2b3c4d5e6f7a8b9c0d1"
}
}
| Field | Description |
|---|
data.errorCode | Numeric error code from Worldpay - use for programmatic handling |
data.errorMessage | Human-readable description of the rejection |
data.transactionId | Mozarto transaction ID - use to look up the failed transaction |
ForumPay#
ForumPay errors include an err string and an err_code identifier in data. Some errors also include an additional object with provider-specific metadata:{
"status": "error",
"message": "Invoice amount is too high.",
"isSuccess": false,
"data": {
"err": "Invoice amount is too high.",
"err_code": "amountExceedsTransactionLimit",
"additional": {
"limit": "8486.30",
"invoice_currency": "EUR"
},
"transactionId": "64a1f2b3c4d5e6f7a8b9c0d1"
}
}
| Field | Description |
|---|
data.err | Human-readable error string from ForumPay |
data.err_code | Machine-readable error code from ForumPay - use this for programmatic handling |
data.additional | Optional object with provider-specific context (e.g. transaction limits, currency). Present on some errors only |
data.transactionId | Mozarto transaction ID - use to look up the failed transaction |
ForumPay Pay-Out errors follow the same structure. err_code values are camelCase strings defined by ForumPay (e.g. amountExceedsTransactionLimit). The additional field is not guaranteed on every error - check for its presence before accessing its properties.PayOne#
PayOne errors include a normalized errorCode at the top level. The raw PSP message is kept in data.error for backward compatibility:{
"status": "error",
"isSuccess": false,
"errorCode": "INVALID_PSP_CREDENTIALS",
"message": "Payment could not be processed due to invalid PSP credentials.",
"transactionId": "64a1f2b3c4d5e6f7a8b9c0d1",
"errors": [],
"data": {
"error": "Invalid account details"
}
}
| Field | Description |
|---|
errorCode | Normalized Mozarto error code - use this for programmatic handling. See Normalized error codes |
message | Friendly message mapped from errorCode - safe to display to end users |
data.error | Raw error string from PayOne - kept for backward compatibility |
Use errorCode for branching logic. data.error contains the raw PSP value for integrations written against the previous format.Gigadat#
Gigadat errors use the standard top-level errors array. There is no provider-specific data field:{
"status": "error",
"message": "Error",
"isSuccess": false,
"errors": [
"Amount should be greater than 12. Current value is 10."
]
}
| Field | Description |
|---|
errors | Array of validation or rejection strings returned by Gigadat - may contain one or more messages |
message | Always "Error" for Gigadat rejections - use errors[0] for the specific reason |
Gigadat Pay-Out (ETO and ACH) returns the same error shape. The errors array always contains at least one message.For 500 responses, Gigadat returns data as a string with the provider's error detail rather than null:{
"status": "error",
"message": "Internal server error",
"isSuccess": false,
"data": "CPI Payload validation failed: Mobile must be 10 digits (5551234567) or 11 digits with country code (15551234567)"
}
Read data as a string when handling Gigadat 500 responses.ForumPay Pay-Out - on hold (not an error)#
A successful ForumPay Pay-Out returns 200 OK with transaction_status: "On Hold", not an error response. The pay-out is held for admin approval before processing:{
"status": "success",
"message": "Transaction is on hold",
"isSuccess": true,
"data": {
"invoice_currency": "EUR",
"invoice_amount": "13.00",
"currency": "BTC",
"payment_source": "cash",
"wait_time": "20 minutes",
"network_processing_fee": "0.00000735",
"rate": "68899.7244",
"amount_exchange": "0.00018868",
"amount": 13,
"fast_transaction_fee": "0.00001044",
"fast_transaction_fee_currency": "BTC/kB",
"payment_id": "1a52f405-5652-4fb6-b37f-538e1feb24d0",
"reference_no": "6a01ed09b681e530b9f26584",
"address": "btc-1eda64a85da94d71a2ac5ed84e929553",
"access_token": "<forumpay-access-token>",
"transactionId": "6a01ed09b681e530b9f26584",
"merchantReference": ""
}
}
Do not treat this as a failure. Wait for the webhook with a terminal transaction_status before crediting or debiting the user.
Retry guidance#
Retry only when the failure is likely transient. Retrying a request with invalid data can create noise and slow down recovery.When errorCode is present, use it to determine retryability: PSP_TIMEOUT, PSP_UNAVAILABLE, and PSP_RATE_LIMITED are safe to retry with backoff. All other codes indicate a permanent failure - fix the request or configuration before retrying.When retrying 500 errors, use exponential backoff (for example: 1s, 2s, 4s, 8s; cap at 30s) and stop after a small number of attempts.Modified at 2026-07-28 13:34:08