Troubleshooting asynchronous transactions
Background |
---|
Before starting this tutorial, make sure you understand the following topics from the Quick start section:
|
Asynchronous transactions, such as with a 3DS payment flow may entail more complex troubleshooting than a normal payment flow. Therefore, Nexio has provided an API endpoint for tracking the status of an asynchronous transaction. This tutorial and troubleshooting information are meant to provide additional details about how to use it.
For this tutorial, we assume that you have already completed the steps in Using 3DS to run transactions.
Note
In order to effectively process and manage 3DS transactions, you need to be aware of the following:
- Nexio strongly recommends that you include an order number with each transaction. Ideally, this value should be unique to the merchant. If you run 3DS transactions and you do not use a unique order number, there will be payment flows that you won't be able to reconcile.
Nexio recommends a format for the order number of a unique value that also includes an attempt number so that you can track attempts per order, such as when a payment attempt fails. For example, something like[order_number]-[attempt_number]
.- Nexio highly recommends that you configure and use webhooks. For more information about doing this, see Webhooks.
- Nexio suggests that you configure listeners on the merchant website for receiving events. For more information about how this works, see steps 2 and 6 in the Creating a card checkout page with the iframe tutorial.
For 3DS, the payment flow is as follows:
- If you need to save a payment card:
- Get a one-time-use token, making sure that 3DS is enabled.
- Use that one-time-use token to save the payment card.
- Save the card token for later use.
- Run the transaction using a saved card token or full card information.
- Put the 3DS redirect link as the SRC for an iframe or an HTML element such as a link. Save the
asyncTraceId
to use for tracking the transaction and for troubleshooting. - Depending on verification needs, the customer may either get redirected to their bank's 3DS page where they can authenticate or the redirect happens behind the scenes and the bank automatically authenticates the customer.
- The 3DS process completes and returns control to the merchant site, where you can display a payment confirmation page.
Sending the paymentType
Nexio requires that you send the appropriate paymentType
parameter and value in your request to Create one-time-use token. Sending an incorrect value may result in fines to the merchant account from card schemes (Mastercard, Visa, and so forth).
You can see more information about the various states here: Payment type (paymentType) in the Constant transaction values topic.
If you are having trouble with a 3DS transaction, you should check to make sure that the paymentType
is being set appropriately for the transaction.
Customer not present
If you use a value of initialMoto
, this means that the transaction was captured in a virtual terminal when customer card information was received over the phone, through mail, or via fax. In this case, you may not be able to do a recurring payment later with that card. For subsequent transactions that are supported by the gateway or processor, use scheduled
, unscheduledCit
, or unscheduledMit
.
Customer present (or customer-initiated)
If you use a value of initialScheduled
, this means that the customer is present (or they initiate it on a website) and you are doing a transaction that will be the first in a series of transactions on a fixed schedule. Any subsequent transactions (recurring or using the same card) will be scheduled
.
You may also use a value of initialUnscheduled
if you know that there will not be any future scheduled or recurring transactions (such as an ad hoc, card-on-file transaction). If you are not sure if you will have scheduled transactions, you should still use this type. Any subsequent transactions (using the same card) need to be either unscheduledCit
or unscheduledMit
.
Later transactions
Any subsequent transactions for that same card need to use a specific paymentType, depending on what it is and what the first paymentType was.
- Use
scheduled
if the first one wasinitialScheduled
(customer present) orinitialMoto
(customer not present). - Use
unscheduledCit
for a customer-initiated transaction and if the first one wasinitialUnscheduled
(customer present) orinitialMoto
(customer not present). - Use
unscheduledMit
for a merchant-initiated transaction (no 3DS verification will be possible) and if the first one wasinitialUnscheduled
(customer present) orinitialMoto
(customer not present).
Handling the 3DS flow
When the customer goes to pay, the system determines whether the 3DS flow needs to be used.
Note
If you are using the payment iframe (Run card transaction with iframe), Nexio handles the redirect flow for you.
One of the first checks that your webpage should make is on the response from the payment. If the 3DS payment flow is required, the response includes a "redirect" status
. Otherwise, the response is a normal payment response. So, you could have code like the following to check for the redirect status option:
// making the payment request. `formData` includes the body of the payment request,
// with all required parameters
fetch('http://localhost:3000/pay', {
method: 'POST',
body: JSON.stringify(formData),
headers: {
'Content-Type': 'application/json'
}
}).then(function (response) {
return response.json();
}).then((objData) => {
if (objData.status === "redirect") {
// set actions such as showing the 3DS iframe, logging the response,
// saving the objData.asyncTraceId, setting the SRC of the iframe
// as specified in the response
}
else {
// this only happens for non-3DS payment flow
}
});
return false;
}
Note the if
clause that is looking for objData.status
. A redirect response when 3DS is required looks like the following:
{
merchantId: '[merchant_id]',
status: 'redirect',
message: 'Provide redirect url in iFrame to shopper to complete 3ds authentication and transaction',
redirectUrl: 'https://api.nexiopaysandbox.com/pay/v3/threeDS/frame?token=[random_token]',
asyncTraceId: '[random_token]',
'random-[nnnn]': '[random_value]'
}
{
error: 446,
message: '{"response":{"rmsg":"Authentication Failed"}}'
}
{
error: 409,
message: 'Either the routing rules (Dashboard Payment Routing and/or paymentOptionTag) filtered out all possible Merchants, or the filtered Merchants do not have this paymentMethod and currency combination configured. Please check your request, edit your Dashboard Payment Routing rules in the Nexio Dashboard Settings or contact integration support.',
}
You may also want an else if
set of clauses to capture some errors that may occur as you are getting things set up:
- An
objData.error
may be "446". This means that 3DS is not enabled correctly for the account. Contact Integrations support for assistance. - An
objData.error
may be "409". This means that 3DS has not been correctly configured or the data from the transaction is routing the transaction to a connection that does not support 3DS or that the routing rules have filtered out all possible connections and so no payment can be sent. Look on the backend server at your one-time-use token code and your run transaction code to see if any processingOptions, currency, item information, or paymentType is routing the transaction inappropriately for your 3DS flow.
Next, you should also save the asyncTraceId
from the redirect response. This can happen at the frontend, but you may also want to do it on your backend server so you can save it to use for tracking and troubleshooting. The following shows potential code that notes the ID:
app.post('/pay', (req, res) => {
// call separate function to do the payment request
return runCardTransactionFunction(req.body).then((response) => {
// log response information
console.log('------->run card response', response);
// check for a redirect response
if (response.status === 'redirect') {
// set a variable to the asyncTraceId and log it
asyncTraceId = response.asyncTraceId;
console.log('------->asyncTraceId for troubleshooting', asyncTraceId);
}
// return the entire response to the frontend
return res.json(response);
})
});
// added to function where payment response gets received
console.log('------->response Data for 3DS redirect', objData);
currentAsyncTraceId = objData.asyncTraceId
// added to listeners
if (message.data.event === 'initiate') {
console.log('Starting 3DS payment flow for asyncTraceId: ', currentAsyncTraceId);
}
And, if you have Webhooks set up, you can also receive updates about transactions and create backend code to handle those updates with the View transaction async status endpoint and the transactions endpoints, such as View transactions.
3DS states
Part of troubleshooting asynchronous transactions includes understanding the different states that are possible and where problems might occur in each state.
These states start with the server returning that redirect
status from a payment request. You can then use the asyncTraceId
value with the View transaction async status endpoint to track which state the transaction is in.
processFromApi
The first state that happens with a 3DS transaction is processFromApi
.
This state begins with a request to the "Run card transaction" or "Run card transaction with iframe" endpoint and ends with the response with the URL for 3DS redirection.
For this state, the initiatedAt
date and time is the moment that the payment request was sent to Nexio.
The async trace state should be redirectUrlReturnedFromGateway
, indicating that Nexio returned the URL. If you see any other state, you should contact Integrations support for assistance.
iframe
The next state is iframe
.
This state begins when the webpage loads the iframe. It ends when the customer clicks the Confirm button to be redirected to the bank's page. For this flow, the async trace state will be loaded
, indicating that the iframe loaded, or submitted
, indicating that the customer clicked the Confirm button in the iframe. If, instead, the customer clicks Cancel in the iframe, the system returns a 481 error indicating that the user canceled the request and the state for this step stays at loaded
. If the customer never clicks either button, the state stays at loaded
. In this situation, you need to check the async trace after one hour. If this state is still at loaded
, then you can cancel the order.
However, you can skip this stage by substituting popup
for iframe
in the redirect URL. You would then either load the popup yourself, or you can provide some other kind of interaction that would open the popup (such as your own button). In this case, the date and time information appears for this state, but is copied from the next state, popup. In this flow, the async trace state will always be submitted
.
You may want to include a check on your website to make sure the iframe loads. This will help you troubleshooting errors at that point. You can look for the loaded
event or through a call to the View transaction async status endpoint to check that the state for iframe
is loaded.
popup
Next is popup
.
This state begins when the system opens the bank's 3DS page for customer validation. An event listener for initiate
gets sent to the web browser. It ends when the customer completes (or fails) 3DS validation. Validation failure may occur when the customer does not successfully authenticate with the bank, the customer closes the page without validating, or the customer waits more than an hour to validate.
For this state, the initiatedAt
date and time is when the system successfully loaded the popup (or a new tab) that the bank has for 3DS validation. The async trace state is set to loaded
at this point. When the 3DS authentication step finishes, whether authorized or unauthorized, the state is set to submitted
. If the customer exits the popup before completing the 3DS authentication with the bank, the system returns a 481
error indicating that the user canceled the request and the state for this step stays at loaded
. If the customer never completes the authentication with the bank, the state for this step also stays at loaded
, but no error gets returned. For the first one, make sure to set up a listener or webhook so you can determine when that happens, and then you can cancel the order. For the second one, you need to check the async trace for the transaction after one hour. If it is still at loaded
, then you can cancel the order.
Finally, if you know the popup was initiated (because of the previous state or an event was triggered, but async trace does not show that this popup
state ever happens, you need to wait up to one hour from when the process started. If it is still not triggered, you can either cancel the order and retry with a new order number (because this may result in two transactions being processed) or you can make the order "pending" for up to 24 hours. After that point, the order will fail if it is not submitted.
finale
And the last possible state is finale
.
This state begins when the system get a response from the 3DS provider and returns control to the merchant website. If the authentication was successful, the event listener of processed
gets triggered. If there were connection issues, the system may return an error at this time.
When the async trace status for this state is initiated
, the 3DS redirect has returned control to the merchant's finale page but there was an error. For example, this happens if the customer authenticates on the bank's 3DS page after more than one hour has elapsed. You should search for the transaction with the View transactions endpoint using a filter of the order ID for this transaction. If there is no result, wait at least 16 minutes after the initiatedAt
timestamp for this state before checking again. After that, if there is still not result at that point, resend the transaction.
If the state is error
, this indicates that there was an error between Nexio and the payment connection, or the customer may have failed authentication with their bank. Check the gatewayResponse
and initialTransactionStatus
in the async trace response to get more information for troubleshooting.
Otherwise, the state is responseSent
. This means that Nexio returned a successful or declined payment response. Check the gatewayResponse
and initialTransactionStatus
in the async trace response to get more information about the successful or declined transaction.
A successful response also returns the payment response (see the next section).
Getting a response after 3DS authentication
The next part of the payment process is all about sending a payment request. For 3DS, the customer needs to also be authenticated with their bank.
After customers successfully authenticate, the system attempts to run the transaction.
Upon completion, the response will be returned as a message to the browser.
-
{ "amount": 34.25, "authCode": "035410", "card": {...}, "currency": "USD", "data": {...}, "gatewayResponse": {...}, "id": "[paymentId]", "kountResponse": {...}, "merchantId": "[merchant_id]", "token": {...}, "transactionDate": "2023-01-15T13:19:39.329Z", "transactionStatus": "pending", "transactionType": "sale" }
If you used a test card or information that does not work with the selected gateway connection, you get an error back to the webpage of
435
(or you can see it in the async trace or in a webhook). You may need to go back to the save card stage so you can process the transaction.
Updated about 2 months ago