When Paradise Gateway forwards a transaction to a processor, the processor may return its own error or decline code. The API normalizes these into a consistent response, but the raw processor details are available in processor_response.

Every transaction response contains two layers of information:
| Layer | Fields | Purpose |
|---|---|---|
| Gateway | response_status, response_code, response_message | Normalized result you should use for business logic |
| Processor | processor_response | Raw response from TSYS or Vericheck — useful for debugging |
{
"id": "TRANSACTION-01KEW32V6YNV11T33XGDR7TGWC",
"response_status": "declined",
"response_code": "05",
"response_message": "Transaction declined by the issuer.",
"processor_response": {
"processor_code": "051",
"processor_message": "INSUFFICIENT FUNDS",
"auth_response_code": "51"
},
"correlation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
}Common TSYS auth response codes and what to do:
| Code | Meaning | Action |
|---|---|---|
00 | Approved | Success — fulfill the order |
01 | Refer to issuer | Do not retry — the cardholder should call their bank |
02 | Refer to issuer (special) | Do not retry — possible fraud alert |
05 | Do not honor | Do not retry — ask for a different card |
12 | Invalid transaction | Check your request — wrong transaction type? |
13 | Invalid amount | Verify the amount field |
14 | Invalid card number | Card number failed validation at the processor |
41 | Lost card — pick up | Do not retry — possible fraud |
43 | Stolen card — pick up | Do not retry — possible fraud |
51 | Insufficient funds | Ask the customer for a different card |
54 | Expired card | Ask for an updated card |
61 | Exceeds withdrawal limit | Ask for a different card or smaller amount |
65 | Activity limit exceeded | Retry later or ask for a different card |
91 | Issuer unavailable | Retry with exponential backoff |
ACH errors are typically ACH return codes from the receiving bank:
| Code | Meaning | Action |
|---|---|---|
| R01 | Insufficient funds | Wait and retry, or contact customer |
| R02 | Account closed | Request new bank details; delete the token |
| R03 | No account / unable to locate | Request corrected account number |
| R04 | Invalid account number | Validate and re-enter |
| R08 | Payment stopped | Contact customer to resolve |
| R10 | Customer advises not authorized | Do not retry — investigate |
| R29 | Corporate not authorized | Do not retry — contact the business |
See ACH returns for the full return handling guide.
Build a mapping function to translate processor codes into your application's actions.
PROCESSOR_ACTION_MAP = {
"00": "success",
"01": "refer_to_issuer",
"05": "decline_no_retry",
"12": "invalid_request",
"14": "invalid_card",
"51": "insufficient_funds",
"54": "expired_card",
"91": "retry",
}
NO_RETRY_ACTIONS = {"decline_no_retry", "refer_to_issuer", "invalid_card", "expired_card"}
RETRY_ACTIONS = {"retry"}
def classify_processor_error(processor_response: dict) -> dict:
code = processor_response.get("auth_response_code", "")
action = PROCESSOR_ACTION_MAP.get(code, "unknown")
return {
"action": action,
"retryable": action in RETRY_ACTIONS,
"user_message": get_user_message(action),
"processor_code": code,
"processor_message": processor_response.get("processor_message", ""),
}
def get_user_message(action: str) -> str:
messages = {
"success": "Payment successful.",
"decline_no_retry": "Your card was declined. Please try a different payment method.",
"refer_to_issuer": "Please contact your bank for assistance.",
"insufficient_funds": "Insufficient funds. Please try a different card.",
"expired_card": "Your card has expired. Please use a different card.",
"invalid_card": "Invalid card number. Please check and re-enter.",
"invalid_request": "There was an issue with the payment. Please try again.",
"retry": "Temporary issue. Please try again in a moment.",
}
return messages.get(action, "Payment could not be processed. Please try again.")- Use
response_statusfor flow control — base your approve/decline/retry logic on the normalized gateway fields, not raw processor codes. - Use
processor_responsefor diagnostics — log it for debugging, but don't expose it to customers. - Keep your mapping table current — as you encounter new processor codes in production, add them to your map.
- Alert on unknown codes — if
classify_processor_errorreturnsunknown, log an alert so you can investigate.