Errors will happen while processing payments and there are many types of errors, including the card being denied because of insufficient funds, being expired or the network timing out or the customer cancelling the payment. Below are some best practices for handling errors.
This link will give you some common error results while working with Adyen: https://quilt-payment-api.readme.io/reference/error-handling-adyen
Checking the payment
When you get the payment result back as declined, this is not as applicable because you have the payment result from the gateway which confirms the current state, however when the error occurs because of the system or user, it is important to get the payment status using the Payment GET endpoint. This is because race conditions can occur where you get back the error but the payment completes at the same time (and if it was set to auto-capture, then the funds could already be captured). If after getting the payment details the status is payment_method_requested
then one of the following is recommended:
- Poll and sleep until the payment status changes (this can be applicable in the case of a timeout).
- Cancel the hardware if applicable using the Terminal CANCEL endpoint if you don't desire to wait (remember to check the payment again after making this request).
Reuse external transaction ID (or external payment ID), don't create a new payment intent
When an error occurs and you want to re-try collecting payment from customer, it's tempting to just reset and start over by using a new external_transaction_id
or external_payment_id
and creating and payment. If your error handling is robust and you've followed the above best practice, then this can work, however, if you reuse your external_transaction_id
from the failed attempt and just try to auth again, we will return an error stating that the payment has already been processed with the current status.
Note, if you try and create a new payment with an exiting external_transaction_id/external_payment_id
you will get an error that the payment already exists. If you need to update the payment, use a PUT Request, otherwise, just retry the AUTH.
Why do this?
- It will prevent duplicates: If the an error occurred like a timeout and you are unsure if the payment went through or not, you can retry and if it did succeed, you get an error back that the intent has already been processed. If you don't do this, a double charge can occur and if we don't catch it and do a refund, then a chargeback can occur.
- Logging and debugging: Our logs will show everything associated with that attempt vs multiple payments that are actually the same transaction but look like different transactions to our system. Payment logs are retained for 1-year.
- Hacker prevention: When working with eCommerce web components hackers will find it more difficult to re-use the page for card validation if they have to setup a new transaction vs re-posting the page. And, our internal fraud detection tools can take action sooner.
External transaction ID already used, how to create a new payment correctly
In the case where you want to collect a new payment for the same external transaction id (most likely when a customer wants to pay with multiple payment methods), you will need to create a new payment for each payment method. If you just pass the same external_transaction_id/external_payment_id
when creating the payment, you will get an error that the payment already exists. To get around this, use the known_payment_ids
array when creating the new payment and pass the payment_id
of the previous payments in this array. This will allow you to attach multiple payments to the same external_transaction_id/external_payment_id
.