--- title: "Handle responses" description: "Learn how to resolve Terminal API errors and handle declined payments." url: "https://docs.adyen.com/point-of-sale/error-scenarios" source_url: "https://docs.adyen.com/point-of-sale/error-scenarios.md" canonical: "https://docs.adyen.com/point-of-sale/error-scenarios" last_modified: "2019-08-20T15:14:00+02:00" language: "en" --- # Handle responses Learn how to resolve Terminal API errors and handle declined payments. [View source](/point-of-sale/error-scenarios.md) Terminal API responses inform you about the processing status of your request. The status of your request is communicated in the `Response` object of the API response. The sections below explain the structure of the response and detail the steps you can take to handle common error scenarios, such as: * The request failed because it was invalid. * You made a payment request but didn't receive a result. * The result of your payment request indicates the transaction failed. ## Response object format To be able to resolve issues with your requests, you need to know how Terminal API informs you of the processing status of your request. This is communicated in the `Response` object of the API response, which has: * `Result`: one of the following values: * **Success**: The request succeeded / the transaction was approved on the terminal. * **Partial**: The transaction amount has been partially approved. * **Failure**: The request or transaction didn't succeed. The remaining `Response` fields provide more information about the error, to enable you to determine how to handle it. * `ErrorCondition`: This field is included when the request or transaction fails, and indicates the cause of the failure. * `AdditionalResponse`: More information about the error condition. You'll receive either a string of form-encoded key-value pairs or a Base64 string that you need to decode to get a JSON object. The information in the `Response` object help you to identify if and why a request has failed. ## Invalid message format A `Response` object with `Result` **Failure** and `ErrorCondition` **MessageFormat** indicates there was a mistake in the request you sent. Proceed as follows: 1. Determine what caused the error, based on the `message`, `warnings`, or `errors` in the `AdditionalResponse`. For example, a missing required field or an unexpected field. The following example is for a response indicating that the `Currency` field is missing from the payment request: **Currency missing** ```json { ... "Response":{ "Result":"Failure", "AdditionalResponse": "errors=At%20SaleToPOIRequest.PaymentRequest.PaymentTransaction.AmountsReq%2c%20field%20Currency%3a%20Missing", "ErrorCondition":"MessageFormat" } ... } ``` 2. Refer to the [Terminal API](https://docs.adyen.com/api-explorer/terminal-api/latest/overview) reference if necessary, then manually fix your request and try again. ## Invalid JSON format If your API request does not contain a valid JSON object, you receive a **Bad JSON** HTTP reply that specifies the line number and a description of the issue: **Bad JSON** ```json ["Bad JSON:LINE_NUMBER: DESCRIPTION"] ``` * Manually fix the JSON error on the line mentioned in the HTTP reply and try again. ## Unavailable service A `Response` object with `Result` **Failure** and `ErrorCondition` **UnavailableService** indicates we were unable to implement your request. Proceed as follows: 1. Determine what caused the error, based on the `message`, `warnings`, or `errors` in the `AdditionalResponse`. For example: * You tried to use functionality that the payment terminal doesn't support. * You tried to use a **ProtocolVersion** that the terminal cannot manage. * You tried to use functionality that we do not support. The following example is for a response indicating that there's a mismatch between the protocol versions (2.0 in the request and 3.0 on the terminal): **Unavailable Service** ```json { ... "Response": { "Result": "Failure", "AdditionalResponse": "message=Sale%20Protocol%20Version%202.0%20mismatch%2c%20Version%20implemented%3a%203.0", "ErrorCondition": "UnavailableService" } ... } ``` 2. Depending on the cause of the error, manually fix your request and send it again. For example, after receiving the above failure response you'd specify the same protocol version that the terminal supports. ## No result received We recommend that your integration automatically checks the status of a transaction any time it fails to receive a transaction response. Payment requests time out after a while. If you do not receive a payment response (or you receive a response indicating a time-out) after 120 seconds (local integration) or 150 seconds (cloud integration), and the internet connection hasn't dropped, your integration should automatically check the transaction status. If you do not receive a transaction result, neither synchronously nor asynchronously, proceed as follows: 1. [Make a transaction status request](/point-of-sale/basic-tapi-integration/verify-transaction-status). 2. Determine your next action based on the [TransactionStatusResponse.Response](https://docs.adyen.com/api-explorer/terminal-api/latest/post/transactionstatus#responses-200-Response): | Response | Description | Action | | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `Result` **Success** | The transaction was processed. | Use the `RepeatedResponseMessageBody` to determine how to process the transaction. | | `ErrorCondition` **InProgress** | The payment terminal is waiting for a response from the shopper, or there is a delay with the card issuer. | Continue making a transaction status request for this transaction every five seconds until you receive a response indicating the transaction was processed. | | `ErrorCondition` **NotFound** | Possible causes:- The details you specified in the transaction status request are incorrect. - We did not receive your request; maybe your connection dropped after sending the request. | Possible actions:- Provide the details of the *original* transaction in the `MessageReference` of your transaction status request. - Retry the *original* transaction. | ## Terminal unavailable (cloud integration) When you send a [payment request](/point-of-sale/basic-tapi-integration/make-a-payment) to a payment terminal that is unavailable, the payment cannot be processed. In a cloud integration, the Terminal API generates a **Reject** [event notification](/point-of-sale/design-your-integration/notifications/event-notifications). Note that event notifications are always presented as a `SaleToPOIRequest`. The `EventNotification` body contains: * `RejectedMessage`: a Base64 string containing the payment request that couldn't be processed. Decode this to get the original payment request as a JSON object. * `EventToNotify`: **Reject** * `EventDetails`: a message indicating why the payment terminal is unavailable. Here's an example event notification for an unavailable payment terminal in a cloud integration: **Terminal unavailable** ```json { "SaleToPOIRequest": { "EventNotification": { "EventToNotify": "Reject", "EventDetails": "message=Did+not+receive+a+response+from+the+POI.", "RejectedMessage": "ewoi...0KfQo=", "TimeStamp": "2020-03-31T10:28:39.515Z" }, "MessageHeader": { "DeviceID": "666568147", "MessageCategory": "Event", "MessageClass": "Event", "MessageType": "Notification", "POIID": "P400Plus-123456789", "ProtocolVersion": "3.0", "SaleID": "saleid-4c32759faaa7", "ServiceID": "31122609" } } } ``` The steps that you can take, relate to the `EventDetails` message you receive: #### Did not receive a response ```raw "message=Did+not+receive+a+response+from+the+POI." ``` This message indicates that the request was sent but the payment terminal didn't respond, possibly because the WebSocket is down at the terminal. * [Make a transaction status request](/point-of-sale/basic-tapi-integration/verify-transaction-status) to verify whether the WebSocket connection has been restored and the payment is now processed. #### Failed to send message ```raw "message=Failed+to+send+message+to+POI.+There+may+be+a+network+issue+or+it+may+not+have+the+websocket+connected." ``` This message indicates that probably the WebSocket for the payment terminal is not available on the cloud router for Terminal API. * Check the WebSocket connection: * The terminal display should have a cloud icon in the top row. * [Check the cloud connection](/point-of-sale/diagnostics/check-cloud-connection) from your Customer Area, using an API request, or on the terminal itself. #### Unknown POIID ```raw "message=Unknown+POIID+P400Plus-123456789" ``` This message indicates that the terminal ID (POIID) in the payment request is incorrect, or that the terminal is in the inventory of the Company account and hasn't been [assigned](/point-of-sale/managing-terminals/assign-terminals) to a merchant account or store that allows processing payments. 1. On the payment terminal, go to the [**Device info** ](/point-of-sale/menu-access)menu option and verify that the terminal ID in the format *\[device model]-\[serial number]* matches the POIID that you specified in the payment request. For example, P400Plus-123456789.\ If the POIID matches, go to the next step. 2. Verify that the payment terminal is assigned to a merchant account or store. You can do this using a GET [/terminals](https://docs.adyen.com/api-explorer/Management/latest/get/terminals) request, or using your [Customer Area](https://ca-test.adyen.com/). ## Declined payment When the [PaymentResponse.Response](https://docs.adyen.com/api-explorer/terminal-api/latest/post/payment#responses-200-Response) includes `Result` **Failure** and one of the [error conditions](#error_conditions) listed below, the transaction was declined.\ The `AdditionalResponse` has more information about why the transaction was declined in the `refusalReason` and `message` fields. These fields are our mapping of the response we receive from acquirers and issuers. Here's an example failure response for a declined payment: **Additional response** ```json { ... "Response": { "Result": "Failure", "AdditionalResponse": "refusalReason=214%Declined%20online...&message=CANCELLED...", "ErrorCondition": "Refusal" } ... } ``` When your payment request is declined, you need to determine whether you can retry it: 1. Check the [ErrorCondition](https://docs.adyen.com/api-explorer/terminal-api/latest/post/payment#responses-200-Response-ErrorCondition) in the `PaymentResponse.Response`, because in many cases this already indicates whether you can retry the transaction.[]() | Error condition | Retry? | | ------------------- | ------------------------------------------------------------------------------------------- | | **Aborted** | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | **Busy** | See next step | | **Cancel** | See next step | | **DeviceOut** | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | **InvalidCard** | See next step | | **NotAllowed** | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | **Refusal** | See next step | | **UnreachableHost** | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | **WrongPIN** | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | 2. For the error conditions **Cancel**, **InvalidCard**, and **Refusal**, check the `AdditionalResponse` for the `refusalReason` and `message`. For the error condition **Busy**, check the response for a `serviceId`. You can use this if you want to cancel the transaction. You can use the `ErrorCondition` to code your POS app. The `refusalReason` and `Message` fields are included for additional insight, and should not be coded against.\ The `serviceId` can be used by the POS app to cancel a transaction. Select the tabs for details. ### Tab: Cancel | ErrorCondition | refusalReason | message | Retry? | | -------------- | -------------------------- | -------------------- | ------------------------------------------------------------------------------------------- | | Cancel | Approved | APPROVED | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | Cancel | (all other refusalReasons) | (all other messages) | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | The `ErrorCondition` **Cancel** can be caused by a device [time-out](#time-out). ### Tab: Busy | ErrorCondition | serviceId | message | Retry? | | -------------- | ---------- | ----------------------------------------------------------------- | -------------------------------------------- | | Busy | 1234567890 | Forbidden Request, Service Dialogue PaymentRequest is in Progress | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | Busy | | ADMIN\_MENU | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | Busy | | (all other messages) | ![-x-](/user/data/smileys/emoji/x.png "-x-") | Using the `serviceId` you can make an [`AbortRequest` ](/point-of-sale/basic-tapi-integration/cancel-a-transaction#cancel-from-register)to cancel the in-progress transaction that the terminal is busy with. ### Tab: InvalidCard | ErrorCondition | refusalReason | message | Retry? | | -------------- | ------------------------------------- | ------------------------------------------ | ------------------------------------------------------------------------------------------- | | InvalidCard | Card data authentication failed | DECLINED | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | InvalidCard | No checking account available on Card | NO\_CHECKING\_ACCOUNT\_AVAILABLE\_ON\_CARD | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | InvalidCard | No savings account available on Card | NO\_SAVINGS\_ACCOUNT\_AVAILABLE\_ON\_CARD | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | ### Tab: Refusal | ErrorCondition | refusalReason | message | Retry? | | -------------- | --------------------------------------------------- | ------------------------------ | ------------------------------------------------------------------------------------------- | | Refusal | Acquirer Error | ERROR | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | AID banned | ERROR | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | Refusal | Always refused | DECLINED | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | Refusal | Amount too low to be accepted by Card Network | DECLINED | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | Refusal | Card is blocked | BLOCK\_CARD | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | Refusal | Card requires online pin | PIN\_REQUIRED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | CVC Declined | CVC\_DECLINED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | declined | DECLINED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Declined Non Generic | DECLINED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Do Not Honor | DECLINED | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | Refusal | Expired Card | CARD\_EXPIRED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Issuer Suspected Fraud | ISSUER\_SUSPECTED\_FRAUD | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | Refusal | Mobile PIN required | MOBILE\_PIN\_REQUIRED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Not enough balance | NOT\_ENOUGH\_BALANCE | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Not Submitted | NOT\_SUBMITTED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Not supported | NOT\_SUPPORTED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Pin tries exceeded | PIN\_TRIES\_EXCEEDED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Pin validation not possible | PIN\_VALIDATION\_NOT\_POSSIBLE | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | Refusal | Refused | DECLINED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Restricted Card | RESTRICTED\_CARD | ![-x-](/user/data/smileys/emoji/x.png "-x-") | | Refusal | Timeout waiting for card after contactless fallback | CONTACTLESS\_FALLBACK | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Transaction Not Permitted | TRANSACTION\_NOT\_PERMITTED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Withdrawal amount exceeded | WITHDRAWAL\_AMOUNT\_EXCEEDED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | | Refusal | Withdrawal count exceeded | WITHDRAWAL\_COUNT\_EXCEEDED | ![-white\_check\_mark-](/user/data/smileys/emoji/white_check_mark.png "-white_check_mark-") | For more information, see our reference documentation for [refusal reasons](/point-of-sale/error-scenarios/refusal-reasons-pos). If you enabled receiving the `refusalReasonRaw` field in the `AdditionalResponse`, also see our reference documentation for [raw acquirer responses](/point-of-sale/error-scenarios/raw-acquirer-responses). The `refusalReasonRaw` provides additional information. But if you base your code on it, that might break your integration because acquirers and issuers sometimes change their raw responses without notice. 3. If applicable, retry the transaction. ## Time-out Various time-outs can occur during a transaction: * A [processing time-out](/point-of-sale/error-scenarios/pos-timeouts#processing-time-out). You receive a **Failure** response and the transaction is cancelled. * A [device time-out](/point-of-sale/error-scenarios/pos-timeouts#device-time-out). You receive a **Failure** response and the transaction is cancelled. * A [request time-out](/point-of-sale/error-scenarios/pos-timeouts#request-time-out). You receive an event notification and the transaction can still be completed on the payment terminal. | Time-out | How to recognize | Action | | ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- | | Processing time-out | Transaction response with: `Response.Result`: **Failure** `ErrorCondition`: **Communication timeout** | Retry the transaction using a different card or payment method. | | Device time-out | Transaction response with: `Response.Result`: **Failure** `ErrorCondition`: **Cancel** `AdditionalResponse`: indicates the type of device time-out | Retry the transaction. | | Request time-out | Event notification with: `EventToNotify`: **Reject** `EventDetails`: **message=Timed+out+waiting+for+response+from+POI.** | [Make a transactions status request](/point-of-sale/basic-tapi-integration/verify-transaction-status) to see if the transaction has been processed. | ## Error condition comparison The table below compares error conditions and troubleshooting steps specific to making a `PaymentRequest`, `TransactionStatusRequest`, or `ReversalRequest` (a [referenced refund](/point-of-sale/basic-tapi-integration/refund-payment/referenced)). | Error condition | PaymentRequest | TransactionStatusRequest | ReversalRequest | | ------------------------------------------------- | ----------------------------------------- | --------------------------------------------- | ---------------------------------------- | | Aborted | Retry | *not applicable* | Optionally retry | | Cancel | See [Declined payment](#declined-payment) | *not applicable* | *not applicable* | | DeviceOut | Wait and retry | Wait and retry | Wait and retry | | InProgress | *not applicable* | See [No result received](#no-result-received) | *not applicable* | | InvalidCard | See [Declined payment](#declined-payment) | *not applicable* | *not applicable* | | [Invalid message format](#invalid-message-format) | | | | | NotAllowed | Do not retry | Wait and retry | Wait and retry or Retry different device | | NotFound | Manual recovery | See [No result received](#no-result-received) | Manual recovery | | Refusal | See [Declined payment](#declined-payment) | *not applicable* | Manual recovery | | [Unavailable service](#unavailable-service) | | | | | UnreachableHost | Retry | Retry | Retry | | WrongPIN | Retry | *not applicable* | *not applicable* | ## Unexpected card entry modes A payment can fail if it is not within the transaction limits that you set or if the entry mode is not supported. For example, making a contactless chip transaction that is above the **Contactless reader limit**.\ You can check the `posEntryMode` inside the `AdditionalResponse` to see whether a card, a QR code, or another entry mode was used to make the transaction. The `posEntryMode` values can be: | Entry mode | Description | | ------------------ | ---------------------------------------------------------------------------------------------------------------------------- | | **CheckReader** | Check reader | | **Contactless** | Magnetic Stripe Contactless card reader conform to ISO 14443 | | **File** | Account data on file | | **ICC** | Contact ICC (asynchronous) | | **Keyed** | Manual key entry | | **MagStripe** | Magnetic stripe card reader | | **Manual** | Reading of embossing or optical character recognition (OCR) of printed data either at time of transaction or after the event | | **RFID** | Payment instrument information taken from RFID | | **Scanned** | Scanned by a barcode reader | | **MagStripe** | Magnetic stripe card reader | | **SynchronousICC** | Contact ICC (synchronous) | | **Tapped** | Contactless card reader | In some cases, you may want to enforce using a specific entry mode, for example when making a [Manual key entry](/point-of-sale/enter-payment-manually/) payment. You can do this by specifying one of the entry modes from the table inside the [TransactionConditions.ForceEntryMode](https://docs.adyen.com/api-explorer/terminal-api/latest/post/payment#request-PaymentTransaction-TransactionConditions) array of the payment request: **Manual key entry payment** #### JSON ```json { "SaleToPOIRequest":{ "MessageHeader":{ "ProtocolVersion":"3.0", "MessageClass":"Service", "MessageCategory":"Payment", "MessageType":"Request", "ServiceID":"037", "SaleID":"POSSystemID12345", "POIID":"P400Plus-275040702" }, "PaymentRequest":{ "SaleData":{ "SaleToAcquirerData":"", "SaleTransactionID":{ "TransactionID":"8377PME_POS", "TimeStamp":"2021-01-19T11:03:39.000Z" } }, "PaymentTransaction":{ "AmountsReq":{ "RequestedAmount":17.50, "Currency":"EUR" }, "TransactionConditions":{ "ForceEntryMode":[ "Keyed" ] } } } } } ``` #### Java ```java String POIID = "YOUR_TERMINAL_ID"; String serviceID = "YOUR_UNIQUE_ATTEMPT_ID"; String saleID = "YOUR_CASH_REGISTER_ID"; String transactionID = "YOUR_UNIQUE_TRANSACTION_ID"; SaleToPOIRequest saleToPOIRequest = new SaleToPOIRequest(); MessageHeader messageHeader = new MessageHeader(); messageHeader.setPOIID(POIID); messageHeader.setMessageClass( MessageClassType.SERVICE ); messageHeader.setMessageType( MessageType.REQUEST ); messageHeader.setProtocolVersion("3.0"); messageHeader.setServiceID(serviceID); messageHeader.setSaleID(saleID); messageHeader.setMessageCategory( MessageCategoryType.PAYMENT ); saleToPOIRequest.setMessageHeader(messageHeader); PaymentRequest paymentRequest = new PaymentRequest(); PaymentTransaction paymentTransaction = new PaymentTransaction(); AmountsReq amountsReq = new AmountsReq(); amountsReq.setRequestedAmount( BigDecimal.valueOf(17.5) ); amountsReq.setCurrency("EUR"); paymentTransaction.setAmountsReq(amountsReq); TransactionConditions transactionConditions = new TransactionConditions(); transactionConditions.getForceEntryMode().add( ForceEntryModeType.KEYED ); paymentTransaction.setTransactionConditions(transactionConditions); paymentRequest.setPaymentTransaction(paymentTransaction); SaleData saleData = new SaleData(); saleData.setSaleToAcquirerData(""); TransactionIdentification saleTransactionID = new TransactionIdentification(); saleTransactionID.setTransactionID(transactionID); saleTransactionID.setTimeStamp(DatatypeFactory.newInstance().newXMLGregorianCalendar(new GregorianCalendar())); saleData.setSaleTransactionID(saleTransactionID); paymentRequest.setSaleData(saleData); saleToPOIRequest.setPaymentRequest(paymentRequest); terminalAPIRequest.setSaleToPOIRequest(saleToPOIRequest); ``` ## See also * [Refusal reasons](/point-of-sale/error-scenarios/refusal-reasons-pos) * [Raw acquirer responses](/point-of-sale/error-scenarios/raw-acquirer-responses) * [Verify transaction status](/point-of-sale/basic-tapi-integration/verify-transaction-status) * [Time-outs](/point-of-sale/error-scenarios/pos-timeouts)