Handling 101 Response Codes
Complete guide for handling 101 response codes from 3DS transactions, Stripe requires_action status, and PayPal processing workflows.
Reading the Response Code
When processing orders, there are times in the response where you will get a successful response accompanied with a response_code=101. What this means is that the transaction was approved, but there is additional information required in order for the order to be completed. Typically in the response you will also see a post_data response. Depending on the gateway and payment method, the post_data value will be one of two formats:
- A redirect URL — A URL where you should redirect the customer to complete or verify the transaction (e.g., 3DS hosted page, PayPal, Afterpay/Klarna).
- A JSON string — A JSON object indicating that the next action should be handled client-side using the Stripe JS SDK (common when using digital wallets, payment tokens, or certain 3DS flows through Stripe).
Below are some examples in which you would see a 101 response, and what you need to do to complete the order.
3DS Transactions
Third Party ProvidersIf you are using a third party 3DS provider such as PAAY, this section will not relate to you; authentication is handled by PAAY and only the variables generated by PAAY would need to be passed to Vrio and you would not need to handle 101 responses. View this article for more information.
3D Secure (3DS) is an authentication method that provides an additional layer of authentication for credit card transactions. 3DS asks your customers to verify their identity with the card issuer during payment.
To successfully handle 3DS transactions, you need to pass a redirect_url when attempting to process an order over the API. This URL is something that you host on your end that will tell the browser to go after the customer has verified their transaction.
When this happens, you will need to send your customer to the URL that was returned in the post_data response. Once this process is completed, the customer will be redirected back to the redirect_url that you specified at the time the order was processed.
Once the user is redirected back to your hosted page, you will need to use the API method POST /orders/{order_id}/complete method posting the following values. (Note: when using the Legacy API, use the POST /order/doProcess3ds method)
- transaction_token = This would be the ID that the processor is returning as a URL variable to your hosted redirect_url. For example, for Stripe this will be the payment_intent.
- merchant_id = This is an optional field but recommended if you are using a payment router and have multiple merchants that can handle the same payment method for the order.
Stripe
There are instances where the Stripe gateway will return a requires_action status. When this happens, the Vrio API returns a response_code=101 and a post_data field. Depending on how Stripe determines the next action should be handled, the post_data will contain one of two formats:
Format 1: Redirect URL
This is the traditional flow. Stripe returns a hosted URL for the customer to complete verification (e.g., 3DS challenge page). Redirect the customer to the URL in post_data:
{
"success": true,
"response_code": 101,
"post_data": "https://hooks.stripe.com/3d_secure_2/hosted?merchant=XXXXXXX&payment_intent=XXXXXX",
"order_id": 12345
}After the customer completes verification, they will be redirected back to the redirect_url you specified when processing the order. Then complete the order using POST /orders/{order_id}/complete with the payment_intent from the query string as the transaction_token.
Format 2: JSON — Stripe SDK (Digital Wallets & Tokens)
When using digital wallets (Apple Pay, Google Pay), payment tokens (confirmation tokens, payment method tokens), or certain card configurations, Stripe may return a use_stripe_sdk next action instead of a redirect URL. In this case, post_data will be a JSON string:
{
"success": true,
"response_code": 101,
"post_data": "{\"next_action\":\"use_stripe_sdk\",\"client_secret\":\"pi_3T2xxxx_secret_xxxx\"}",
"order_id": 12345
}To handle this, you must use the Stripe.js SDK on the client side:
Step 1: Parse the post_data JSON and extract the client_secret.
Step 2: Call stripe.handleNextAction() with the client_secret:
// Parse the post_data to determine the type
let postData = response.post_data;
try {
const parsed = JSON.parse(postData);
if (parsed.next_action === 'use_stripe_sdk') {
// Use Stripe.js SDK to handle the next action
const { paymentIntent, error } = await stripe.handleNextAction({
clientSecret: parsed.client_secret
});
if (error) {
// Authentication failed — show error to customer
console.error('Authentication failed:', error.message);
} else if (paymentIntent && paymentIntent.status === 'requires_capture') {
// Authentication succeeded — complete the order in Vrio
await fetch(`https://api.vrio.app/orders/${orderId}/complete`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-Api-Key': 'YOUR_VRIO_API_KEY'
},
body: JSON.stringify({
transaction_token: paymentIntent.id,
merchant_id: merchantId
})
});
}
}
} catch (e) {
// post_data is a URL, not JSON — use redirect flow
window.location.href = postData;
}Step 3: On success, complete the order using POST /orders/{order_id}/complete with the paymentIntent.id as the transaction_token — the same as in the redirect flow.
Which format will I get?The format depends on how the payment was initiated. If you passed a Stripe payment token (e.g.,
ctoken_,pm_) or are using Apple Pay / Google Pay, Stripe will typically return theuse_stripe_sdkJSON format. Browser-based card entry with aredirect_urlwill typically return the redirect URL format. Your integration should handle both.
Determining the Format
A simple way to determine the format is to attempt to parse the post_data as JSON. If it parses successfully and contains next_action: "use_stripe_sdk", use the Stripe.js SDK approach. Otherwise, treat it as a redirect URL:
function handlePostData(postData, orderId, merchantId) {
try {
const parsed = JSON.parse(postData);
if (parsed.next_action === 'use_stripe_sdk') {
// Handle with Stripe.js SDK
return handleWithStripeSDK(parsed.client_secret, orderId, merchantId);
}
} catch (e) {
// Not JSON — it's a redirect URL
}
// Redirect the customer
window.location.href = postData;
}NOTE: If you wish to not handle the requires_action status, check the box on the merchant account labeled Decline Status: Requires Action and Stripe will decline the order with this response code authentication_not_handled. If you do not set the decline with this status and you do not pass a redirect_url, the transaction will sit in a pending status in Vrio.
Stripe.js Reference
For full details on stripe.handleNextAction(), see the Stripe.js SDK Reference.
For a complete server-side finalization example, see Finalize payments on the server in the Stripe docs.
Check out our recipe below for an example of this process.
🦉Stripe Multi-Step Order ProcessingPayPal
You would also see a 101 response when using the PayPal. The flow is the same, in order to complete a PayPal transaction, you would need to send the customer to the URL specified in the post_data response then completed afterwards.
Check out this recipe on how to use PayPal over the Vrio API. And click here to view our guide on Headless Paypal.
🦉Headless PaypalUpdated 29 days ago
