3DS and redirect handling
This guide applies to both Drop-in Checkout and Elements. The return URL handling and query parameter parsing are identical for both integration paths.
When processing payments, some payment methods may require additional customer authentication or authorization steps. This is commonly seen with 3D Secure (3DS) for card payments, as well as alternative payment methods like PayPal, which often redirect customers to their own platforms for authorization. It is critical that your application can handle these redirects properly to ensure a smooth payment experience for your customers.
Read more about the flows that may require redirects in the Payment Flow overview.
When a payment requires additional customer authentication, such as 3D Secure for card payments or authorization through an alternative payment method like PayPal, Odus Checkout will redirect the customer to the appropriate authentication page. After the customer completes the authentication, they will be redirected back to your application using the Return URL you provided during the checkout initialization.
Return URL
Return URL is required for all customer-initiated payments and must be provided when initializing the Checkout SDK. This URL is where the customer will be redirected after completing the authentication process or cancelling the flow. It is important to include any necessary query parameters in the return URL to restore the state of your application after the redirect.
const checkout = new OdusCheckout({
...
returnUrl: 'https://my-website.com/checkout?utm_source=newsletter&session_id=abc123',
...
});
Handling redirect results
Checkout SDK will not emit onPaymentSucceeded or onPaymentFailed events for payments that were authorized through a redirect flow.
When the customer is redirected back to your application after completing the payment process, Odus will append the following query parameters to the return URL:
success: A boolean value indicating whether the payment was successful or not.payment: The ID of the payment.checkoutKey: (optional) The checkout key of the payment, only included for failed payments.error: (optional) A boolean value indicating whether there was an error during the payment process.message: (optional) A user-friendly message that provides additional context about the payment status.
This data should now be used by your application to determine the outcome of the payment and take appropriate actions.
Payment succeeded
https://my-website.com/checkout?utm_source=newsletter&session_id=abc123&success=true&payment=pay_xyz
Successful payments will have success=true and payment=pay_xyz included in the return URL. If you're using the Checkout SDK, you should not re-initialize the SDK as the payment has already been completed and doing so will lead to errors. You may continue with your post-payment logic such as displaying a confirmation message, updating order status, or redirecting the customer to a success page.
Payment failed
https://my-website.com/checkout?utm_source=newsletter&session_id=abc123&success=false&payment=pay_xyz&checkoutKey=chk_xyz&message=Your%20card%20was%20declined
Failed payments will have success=false, and both payment and checkoutKey included in the return URL. Most of the times, a user-friendly message will also be included to provide additional context about the failure (e.g., "Your card was declined", "Insufficient funds"). In rare cases, an error=true parameter may also be included to indicate that an unexpected error occurred during the payment process.
We recommend re-initializing the Checkout SDK with the same configuration used during the previous payment attempt, using the payment and checkoutKey values from the return URL. To reduce friction, you may also pre-fill any previously entered customer information, such as email address as explained in the Configuration guide.
Drop-in Checkout
import { OdusCheckout } from '@odus/checkout';
const searchParams = new URLSearchParams(window.location.search);
const paymentId = searchParams.get('payment');
const checkoutKey = searchParams.get('checkoutKey');
const message = searchParams.get('message');
const isError = searchParams.get('error') === 'true';
if (isError) {
console.error(`Payment ${paymentId} failed with error: ${message}`);
}
const customerEmail = window.localStorage.getItem('customerEmail');
const checkout = new OdusCheckout({
apiKey: 'pk_xyz',
paymentId,
checkoutKey,
// ... other configuration options
initialValues: {
email: customerEmail,
},
});
checkout.mount('#checkout-container');
// Display the error message from the redirect using built-in Alert styling
if (message) {
checkout.displayError(message);
}
Elements
import { OdusElements } from '@odus/checkout/elements';
const searchParams = new URLSearchParams(window.location.search);
const paymentId = searchParams.get('payment');
const checkoutKey = searchParams.get('checkoutKey');
const message = searchParams.get('message');
const isError = searchParams.get('error') === 'true';
if (isError) {
console.error(`Payment ${paymentId} failed with error: ${message}`);
}
const checkout = new OdusElements({
apiKey: 'pk_xyz',
environment: 'test',
returnUrl: 'https://your-website.com/checkout/return',
callbacks: {
onPaymentSucceeded: () => {
window.location.href = '/success';
},
onPaymentFailed: (error) => console.error('Failed', error),
onActionRequired: (url) => {
window.location.href = url;
},
},
});
// Mount elements into your layout
checkout.elements.contact.email.mount('#email-field');
checkout.elements.card.mount('#card-field');
checkout.elements.error.mount('#error-display');
// Display the error message from the redirect
if (message) {
checkout.elements.error.setError(message);
}
// Re-associate the payment
await checkout.associatePayment(paymentId, checkoutKey);
Manual action handling
In some cases, you may want to handle the redirect flow manually instead of relying on the automatic redirect. One of such cases is to display the authentication page within a modal or iframe on your website, rather than navigating away from your site.
Drop-in Checkout
To enable manual handling of redirects in Drop-in, set the manualActionHandling option to true when initializing the Checkout SDK. For more details, refer to the Configuration guide.
When manualActionHandling is enabled, the Checkout SDK will emit an onActionRequired callback when a redirect is needed. This callback provides the url to which the customer should be redirected.
import { OdusCheckout } from '@odus/checkout';
const checkout = new OdusCheckout({
...
manualActionHandling: true,
callbacks: {
onActionRequired: (redirectUrl) => {
openInModal(redirectUrl);
},
...
},
});
Elements
Elements always fires the onActionRequired callback when a redirect is needed — there is no manualActionHandling toggle. Handle the redirect URL in whatever way suits your application.
import { OdusElements } from '@odus/checkout/elements';
const checkout = new OdusElements({
...
callbacks: {
onActionRequired: (redirectUrl) => {
openInModal(redirectUrl);
},
...
},
});
After completing the payment, the customer will still be redirected to the Return URL you provided during initialization, just as in the automatic flow. You will need to handle the redirect results as described in the Handling redirect results section above.