# Adyen drop-in returns from 3DS redirect with no resultCode

## TL;DR
After a 3DS redirect, the resultCode is not in the return URL; it has to be fetched. Take the redirectResult (or the payload/details params) from the return and call /payments/details with them. That call returns the actual resultCode. A missing resultCode on return is normal flow, not an error.

```text
adyen drop-in returns from 3DS redirect with no resultCode
```

## Steps

1. On your return URL handler, collect whatever Adyen appended: redirectResult, payload, or the details object, depending on your integration version. Success check: your handler logs the returned params instead of looking for resultCode.

2. POST those params to /payments/details from your backend. Success check: /payments/details returns a response containing resultCode.

3. Branch on the returned resultCode normally: Authorised goes to fulfillment, Refused to decline messaging, Cancelled to cancellation messaging, Error to your error path. Success check: each outcome routes correctly in a test run.

4. If the return has NO params at all, check your returnUrl: it must match the one sent in the /payments request, and your route must accept the query params (some frameworks strip them). Success check: a test redirect round-trip preserves the params.

5. Guard against expired sessions: if /payments/details says the session is unknown or expired, the shopper took too long or double-submitted; start a fresh payment. Success check: expired sessions produce a clean "session expired, please try again" message.

## When this applies

- Drop-in or Components redirect 3DS flow lands back on your site with no resultCode.
- An agent-built return handler checks for resultCode in the URL and finds nothing.
- You need the canonical "fetch the result after redirect" pattern.

## When it doesn't

- Native 3DS2 challenge (no redirect involved); that uses the challenge-result callback instead.
- Shopper cancels at the challenge; that yields CANCELLED via /payments/details, not a missing resultCode.
- /payments itself errors before any redirect; fix the request first.

## Tool + version compatibility

Adyen Checkout API v68+, Drop-in / Components v5+, redirect-based 3DS (3DS1 fallback and redirect 3DS2).

### "adyen redirectResult missing"
If redirectResult specifically is absent, your returnUrl config or param handling is the suspect; see step 4.

### "adyen 3ds redirect no result"
Same pattern: the result always comes from /payments/details, never from the URL alone.

### "adyen returnUrl empty response"
Check for param stripping by your framework or web server before assuming Adyen sent nothing.

## Why it happens

The redirect flow is asynchronous by design: Adyen sends the shopper to the issuer and back, and the payment outcome is only finalized when your backend asks for it via /payments/details. Agents often assume the redirect return carries the verdict like a normal API response, so they read the URL, find no resultCode, and declare the payment broken.

## Edge cases / pitfalls

- Do not mark the order paid based on the shopper merely returning to your site; only the /payments/details resultCode counts.
- Shoppers who close the tab mid-redirect never return; reconcile these with Adyen notifications or a pending-order sweep.
- The /payments/details call needs the same merchant account and environment as the original /payments call.
- Log the full /payments/details response for redirect flows; debugging them later without it is guesswork.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_LoGewwP0AHp_7UNN8iyBBQ
