How to handle payment.requires_action webhooks without a redirect URL
Last updated: April 22, 2026
Lago's payment.requires_action webhook can fire for two different Stripe 3DS authentication flows, but only one of them includes a redirect URL. Webhook handlers that unconditionally try to extract a redirect URL will throw an error or return a 500 when Stripe uses the other flow.
How Stripe 3DS flows work
When a payment requires strong customer authentication, Stripe uses one of two flows. The redirect_to_url flow sends the customer to a hosted authentication page; Lago includes the URL in next_action.redirect_to_url.url. The use_stripe_sdk flow is handled natively by Stripe without any redirect; next_action will contain a type field set to use_stripe_sdk but no URL.
Both flows produce a payment.requires_action webhook from Lago, so the type field inside next_action is the only reliable way to tell them apart.
How to resolve the issue
Update your webhook handler to branch on next_action.type before attempting to extract a redirect URL:
next_action = payment["next_action"]
if next_action["type"] == "redirect_to_url":
# redirect to next_action["redirect_to_url"]["url"]
elif next_action["type"] == "use_stripe_sdk":
# no redirect neededThis prevents your handler from failing when a use_stripe_sdk event arrives without a URL.
How to prevent this from happening again
Treat next_action.type as a required check in any payment.requires_action handler, not an optional field. New Stripe 3DS flow types could be introduced in the future, so a default no-op branch is also worth adding to avoid regressions.
This article reflects guidance drawn from customer case resolutions. It is not officially supported documentation and may not apply to all situations.