TL;DR: This means your /payments/details request is missing the paymentData blob from the first /payments response. Capture action.paymentData server-side when you create the payment, store it across the redirect, and send it back verbatim in /payments/details.

The exact error:

```text
14_002 - paymentData has not been provided in the request
```

## The fix

1. Capture paymentData from the /payments response: read action.paymentData on your server, not in the browser.
   Expected: Your logs show a paymentData string starting with the encrypted blob from Adyen.
2. Store it server-side keyed by your order reference (session, cache, or database) before redirecting the shopper.
   Expected: The value survives the shopper's trip to the bank and back.
3. Send it back verbatim in /payments/details alongside redirectResult or the details object.
   Expected: Adyen returns resultCode Authorised, Refused, or a further action instead of 14_002.

## When this applies

- /payments/details returns 14_002 after a redirect or 3D Secure challenge
- Your logs show the details request has no paymentData field at all
- A shopper completes their bank redirect but the payment never finalizes

## When it does NOT apply

- The initial /payments call, which creates paymentData rather than consuming it
- A 14_003 invalid paymentData error, where the value is present but corrupt (different fix)
- The /sessions + /paymentMethods flow, where the session object carries the state

## Versions

Adyen Checkout API v68 through v71. The /sessions flow uses sessionData instead of paymentData.

## Why it happens

Adyen keeps no server-side link between the redirect return and the original payment except the paymentData blob you echo back. Without it the /payments/details call is an orphan, so validation rejects it before any payment logic runs.

## Edge cases and pitfalls

- paymentData expires after about 3 hours, so a shopper who returns late will hit a different error
- Do not store paymentData in client-side local storage on a shared device; keep it server-side
- The /sessions flow uses sessionData instead; paymentData belongs to the classic /payments/details flow
