To use Adyen with V0 by Vercel, embed the Adyen Web Drop-in or Components UI library in your V0-generated Next.js app and create a Next.js API route that uses your Adyen API key to create a payment session. Adyen's Drop-in handles the entire payment form UI, 3D Secure authentication, and payment method selection — your API route returns the session data and Adyen's SDK takes care of the rest.
Enterprise Payments in V0 Apps with Adyen Drop-in
Adyen powers payments for companies like eBay, Spotify, and McDonald's — and the same payment infrastructure is available to any developer through the Adyen API. For V0 developers building apps that need to accept payments globally with support for cards, wallets, buy-now-pay-later, and local payment methods, Adyen is the enterprise-grade choice. Unlike Stripe, Adyen requires a direct merchant account application rather than instant sign-up, but it offers lower processing fees at scale, more granular fraud controls, and broader global payment method coverage.
Adyen's Web integration uses a session-based flow that keeps your secret API key off the browser. Your Next.js API route calls the Adyen Checkout Sessions endpoint with your API key to create a session object — this session contains a one-time token and all the payment details. The session is sent to the browser, where the Adyen Web SDK reads it and mounts either the Drop-in (a complete payment form with method selection) or individual Components (one component per payment method like AdyenCard, AdyenPayPal, etc.) into a div element. The SDK communicates directly with checkoutshopper-live.adyen.com for the heavy lifting, including 3DS2 authentication challenges.
V0 is ideal for generating the surrounding checkout page: order summaries, product cards, pricing tables, and the confirmation screen after payment. You focus on the business logic and overall UX, while Adyen's Drop-in handles the PCI-compliant payment form rendering. This tutorial covers the complete integration from generating the checkout UI in V0 to testing with Adyen's test card numbers.
Integration method
V0 generates the checkout page layout and surrounding UI. A Next.js API route calls the Adyen Checkout API to create a payment session using your server-side API key. The Adyen Web Drop-in or Components library (loaded via @adyen/adyen-web) mounts into a container div in your React component, handles all payment form rendering, and communicates with Adyen's servers at checkoutshopper-live.adyen.com directly from the browser.
Prerequisites
- A V0 account at v0.dev and a Next.js project to work with
- An Adyen merchant account — apply at adyen.com (test accounts are available immediately at ca-test.adyen.com)
- An Adyen API key from your Customer Area (Developers → API credentials → API key)
- Your Adyen Merchant Account name and Client Key (also in Developers → API credentials)
- A Vercel account for deployment and environment variable configuration
Step-by-step guide
Generate the Checkout Page UI in V0
Generate the Checkout Page UI in V0
Open V0 and describe the checkout experience you want to build. Adyen's Drop-in will occupy a specific container div in your layout — the rest of the page (order summary, product details, trust badges, progress indicators) is entirely up to you and is what V0 excels at generating. Think about your checkout flow: do you want a single-page checkout where everything is visible at once, or a multi-step flow (cart → shipping → payment → confirmation)? Single-page is simpler to build and converts well for low-complexity purchases. For the payment step, all you need is a container element — a div with a specific ID — where the Adyen SDK will inject its own HTML. Ask V0 to generate a realistic-looking checkout page with hardcoded placeholder data so you can see how the full page looks. Include an order summary with item names, quantities, and prices, plus a right column or bottom section reserved for the payment form. Also ask V0 to generate the post-payment confirmation page that users land on after a successful payment — this page reads the payment result from URL query parameters that Adyen appends on redirect. Use V0's Design Mode to polish typography, colors, and spacing so the page matches your brand before adding any payment logic.
Create a checkout page at app/checkout/page.tsx with a two-column layout. Left column: an order summary card showing 3 placeholder line items with name, quantity, and price, a subtotal row, a tax row, and a bold total. Right column: a 'Secure Payment' heading with a lock icon, a div with id='adyen-dropin-container' and className='min-h-48', and a loading skeleton that shows while the payment form is mounting. Also create a confirmation page at app/checkout/confirmation/page.tsx that shows a success message, order number, and a 'Continue Shopping' button.
Paste this in V0 chat
Pro tip: Ask V0 to use a neutral gray background for the adyen-dropin-container div with rounded corners and padding — this creates a natural visual frame for the payment form that Adyen injects.
Expected result: V0 generates a polished two-column checkout page with the payment container div in place, and a separate confirmation page ready to receive the payment result.
Install the Adyen Web SDK and Node.js Library
Install the Adyen Web SDK and Node.js Library
Install two packages: @adyen/adyen-web for the browser-side Drop-in UI, and @adyen/api-library for making server-side calls to the Adyen API from your Next.js API routes. The @adyen/adyen-web package is a client-side library — it gets imported in your React component and mounts the payment form UI into the container div. It communicates directly with Adyen's checkout shopper endpoints (checkoutshopper-live.adyen.com or checkoutshopper-test.adyen.com) from the browser, so you do not need to proxy every payment interaction through your API. The @adyen/api-library package is used exclusively in your Next.js API routes for server-side operations: creating sessions, refunding payments, retrieving payment details, and managing stored payment methods. This separation is important for security — your Adyen API key only ever appears in server-side code. Add both to your package.json and import @adyen/adyen-web CSS in your global stylesheet or layout. The Adyen Web SDK also requires importing its CSS file (node_modules/@adyen/adyen-web/dist/adyen.css) to render correctly — without it the form will be unstyled.
Add @adyen/adyen-web and @adyen/api-library to the package.json dependencies. Import the Adyen CSS in app/globals.css using @import '@adyen/adyen-web/dist/adyen.css'. Create a lib/adyen.ts file that exports an initialized CheckoutAPI from @adyen/api-library configured with process.env.ADYEN_API_KEY and process.env.ADYEN_ENVIRONMENT (either 'TEST' or 'LIVE'). Export the ADYEN_MERCHANT_ACCOUNT from process.env as a named export.
Paste this in V0 chat
1// lib/adyen.ts2import { Client, Config, CheckoutAPI } from '@adyen/api-library';34const config = new Config();5config.apiKey = process.env.ADYEN_API_KEY ?? '';6config.environment = (process.env.ADYEN_ENVIRONMENT as 'TEST' | 'LIVE') ?? 'TEST';78const client = new Client({ config });910export const checkout = new CheckoutAPI(client);11export const MERCHANT_ACCOUNT = process.env.ADYEN_MERCHANT_ACCOUNT ?? '';Pro tip: The Adyen CSS import must be a global import — placing it in app/globals.css ensures it loads for the page that mounts the Drop-in. Importing it only inside the component can cause the styles to flicker on initial render.
Expected result: Both packages are installed, the Adyen CSS is imported globally, and lib/adyen.ts exports the configured CheckoutAPI instance ready for use in API routes.
Create the Payment Session API Route
Create the Payment Session API Route
Build the Next.js API route at app/api/adyen/session/route.ts that your checkout page calls to create a payment session. This is the only Adyen API call that goes through your server — once the session is created, the browser talks to Adyen directly. The session endpoint requires your merchant account, the payment amount (in the smallest currency unit — cents for USD/EUR, pence for GBP), the currency code, a return URL where Adyen redirects after payment (for 3D Secure redirects), and a reference string (your order ID). Optionally include the shopper's email and name for fraud scoring. The session response contains a sessionId and sessionData — both are required by the browser-side SDK. The return URL should point to your confirmation page (e.g., https://your-app.vercel.app/checkout/confirmation) because some payment methods like bank transfers and 3DS2 redirect users away from your site and back. In test mode, use an amount like 1000 (meaning $10.00) and the 'TEST' environment. Adyen's test environment is completely separate from live — test API keys only work against test URLs and do not process real charges. The route should also accept the cart details from the request body so you can pass the real order total dynamically.
Create app/api/adyen/session/route.ts that accepts POST requests with { amount: number, currency: string, reference: string, returnUrl: string } in the body. Import checkout and MERCHANT_ACCOUNT from lib/adyen.ts. Call checkout.sessions() with the PaymentSessionsRequest type, including merchantAccount, amount, currency, reference, and returnUrl. Return the sessionId and sessionData from the response as JSON. Add error handling that returns a 500 status with the error message.
Paste this in V0 chat
1// app/api/adyen/session/route.ts2import { NextRequest, NextResponse } from 'next/server';3import { checkout, MERCHANT_ACCOUNT } from '@/lib/adyen';4import type { CreateCheckoutSessionRequest } from '@adyen/api-library/lib/src/typings/checkout/createCheckoutSessionRequest';56export async function POST(req: NextRequest) {7 try {8 const { amount, currency, reference, returnUrl } = await req.json();910 if (!amount || !currency || !reference || !returnUrl) {11 return NextResponse.json(12 { error: 'amount, currency, reference, and returnUrl are required' },13 { status: 400 }14 );15 }1617 const request: CreateCheckoutSessionRequest = {18 merchantAccount: MERCHANT_ACCOUNT,19 amount: { value: amount, currency },20 reference,21 returnUrl,22 channel: 'Web',23 shopperInteraction: 'Ecommerce',24 };2526 const response = await checkout.PaymentsApi.sessions(request);2728 return NextResponse.json({29 sessionId: response.id,30 sessionData: response.sessionData,31 });32 } catch (error) {33 console.error('Adyen session error:', error);34 return NextResponse.json(35 { error: 'Failed to create payment session' },36 { status: 500 }37 );38 }39}Pro tip: Always generate your order reference before calling the sessions API — use a UUID or your database order ID. Adyen uses this reference to match webhooks to your orders, so it must be unique per transaction.
Expected result: POST requests to /api/adyen/session return a JSON object with sessionId and sessionData. You can verify this in the Vercel dashboard's function logs or using a tool like Postman with your test credentials.
Mount the Adyen Drop-in in Your React Component
Mount the Adyen Drop-in in Your React Component
Now wire the checkout page component to fetch a session from your API route and mount the Adyen Drop-in. The Drop-in must be initialized client-side — import AdyenCheckout from @adyen/adyen-web inside a useEffect hook (not at the top level) to avoid SSR issues, since the Adyen SDK accesses browser APIs like window and document. Alternatively, use Next.js's dynamic import with { ssr: false } to lazy-load the Adyen module. The initialization flow is: (1) fetch the session from /api/adyen/session on component mount, (2) initialize AdyenCheckout with the session data, client key, and environment, (3) create a Drop-in instance from the checkout object, (4) mount the Drop-in into the container div using its ID or a ref. The Drop-in accepts onPaymentCompleted and onError callback functions. The onPaymentCompleted callback fires when the payment is authorized — it receives a result object with a resultCode like 'Authorised', 'Refused', or 'Pending'. On 'Authorised', redirect the user to your confirmation page. The client key (NEXT_PUBLIC_ADYEN_CLIENT_KEY) is different from your API key — it is a public credential used by the browser SDK to identify your merchant account on Adyen's CDN, and it is safe to expose as a NEXT_PUBLIC_ variable.
Update app/checkout/page.tsx to fetch a payment session from /api/adyen/session on mount (POST with amount: 1000, currency: 'USD', reference: a generated UUID, returnUrl: window.location.origin + '/checkout/confirmation'). Store sessionId and sessionData in state. Use useEffect with dynamic import of @adyen/adyen-web to initialize AdyenCheckout with the session, environment set from process.env.NEXT_PUBLIC_ADYEN_ENVIRONMENT, and clientKey from process.env.NEXT_PUBLIC_ADYEN_CLIENT_KEY. Mount a Drop-in into the div with id='adyen-dropin-container'. On onPaymentCompleted, redirect to /checkout/confirmation?resultCode=Authorised. Show a loading state while the session is being fetched.
Paste this in V0 chat
1'use client';23import { useEffect, useState, useRef } from 'react';4import { useRouter } from 'next/navigation';56const ADYEN_ENV = process.env.NEXT_PUBLIC_ADYEN_ENVIRONMENT ?? 'test';7const ADYEN_CLIENT_KEY = process.env.NEXT_PUBLIC_ADYEN_CLIENT_KEY ?? '';89export default function CheckoutPage() {10 const router = useRouter();11 const dropinRef = useRef<HTMLDivElement>(null);12 const [sessionLoading, setSessionLoading] = useState(true);13 const [error, setError] = useState<string | null>(null);1415 useEffect(() => {16 let dropin: { unmount: () => void } | null = null;1718 async function initAdyen() {19 try {20 // 1. Create session21 const res = await fetch('/api/adyen/session', {22 method: 'POST',23 headers: { 'Content-Type': 'application/json' },24 body: JSON.stringify({25 amount: 1000,26 currency: 'USD',27 reference: crypto.randomUUID(),28 returnUrl: `${window.location.origin}/checkout/confirmation`,29 }),30 });31 const { sessionId, sessionData } = await res.json();32 setSessionLoading(false);3334 // 2. Init Adyen Checkout35 const { default: AdyenCheckout } = await import('@adyen/adyen-web');36 const checkout = await AdyenCheckout({37 environment: ADYEN_ENV,38 clientKey: ADYEN_CLIENT_KEY,39 session: { id: sessionId, sessionData },40 onPaymentCompleted(result: { resultCode: string }) {41 router.push(`/checkout/confirmation?resultCode=${result.resultCode}`);42 },43 onError(error: Error) {44 console.error('Adyen error:', error);45 setError('Payment failed. Please try again.');46 },47 });4849 // 3. Mount Drop-in50 if (dropinRef.current) {51 dropin = checkout.create('dropin').mount(dropinRef.current);52 }53 } catch (err) {54 setError('Failed to load payment form. Please refresh the page.');55 setSessionLoading(false);56 }57 }5859 initAdyen();60 return () => dropin?.unmount();61 }, [router]);6263 return (64 <div className="max-w-2xl mx-auto p-6">65 <h1 className="text-2xl font-bold mb-6">Checkout</h1>66 {error && <p className="text-red-600 mb-4">{error}</p>}67 {sessionLoading && <div className="h-48 bg-gray-100 rounded-lg animate-pulse" />}68 <div ref={dropinRef} id="adyen-dropin-container" />69 </div>70 );71}Pro tip: Always call dropin.unmount() in the useEffect cleanup function — failing to unmount causes React to throw 'Target already occupied' errors if the component re-renders or hot-reloads in development.
Expected result: The checkout page loads, fetches a session, and mounts the Adyen Drop-in showing available payment methods. In test mode, the Drop-in shows a card form. Entering Adyen's test card number 4111 1111 1111 1111 with any future expiry and CVC completes a test payment.
Add Environment Variables in Vercel and Switch to Live
Add Environment Variables in Vercel and Switch to Live
Configure all Adyen environment variables in your Vercel project before deploying. Open Vercel → your project → Settings → Environment Variables and add the following variables. ADYEN_API_KEY is your secret key from Customer Area → Developers → API credentials — this must never have the NEXT_PUBLIC_ prefix, as it is a server-side secret. ADYEN_MERCHANT_ACCOUNT is your merchant account name (found in the top-left of your Customer Area dashboard). ADYEN_ENVIRONMENT is the string 'TEST' for test mode or 'LIVE' for production — the @adyen/api-library uses this to route requests to the correct API endpoint. NEXT_PUBLIC_ADYEN_CLIENT_KEY is your client key from API credentials — it uses the NEXT_PUBLIC_ prefix because the browser SDK needs it to communicate with Adyen's CDN. NEXT_PUBLIC_ADYEN_ENVIRONMENT is the lowercase version ('test' or 'live') used by the browser SDK, which has different casing requirements from the server-side library. When you are ready to go live, change both environment variables from TEST/test to LIVE/live and obtain a live API key — live API keys are only issued after your Adyen account team reviews and activates your account. For enterprise payment flows involving marketplace splits, recurring billing, or advanced fraud rules, RapidDev's team can help configure the full Adyen integration including webhook handling and payment result processing.
1# .env.local (development — never commit this file)2# Server-side only (no NEXT_PUBLIC_ prefix)3ADYEN_API_KEY=AQE...your-test-api-key4ADYEN_MERCHANT_ACCOUNT=YourMerchantAccountName5ADYEN_ENVIRONMENT=TEST67# Client-side (NEXT_PUBLIC_ prefix required)8NEXT_PUBLIC_ADYEN_CLIENT_KEY=test_...your-client-key9NEXT_PUBLIC_ADYEN_ENVIRONMENT=testPro tip: Adyen test and live environments use completely separate API keys — a test API key will not work against live endpoints. Always verify your environment variable values match the intended environment before deploying.
Expected result: The app deploys to Vercel and the checkout flow works end-to-end in test mode. Server-side variables are accessible only in API routes, and client-side NEXT_PUBLIC_ variables are included in the browser bundle for the Adyen Web SDK.
Common use cases
One-Page Checkout for E-Commerce
Build a complete checkout page where customers can see their order summary, choose a payment method (card, PayPal, Apple Pay, Google Pay, BNPL), and complete payment without leaving your site. Adyen Drop-in renders all available payment methods in a unified UI based on the customer's location and device.
Create a checkout page with two columns: a left column showing an order summary card with line items, subtotal, tax, and total; and a right column with a 'Payment' heading and a div with id='adyen-dropin-container' where the Adyen Drop-in will be mounted. Add a loading spinner that shows while the payment session is being fetched from /api/adyen/session. Make the page mobile-responsive with the order summary stacking above the payment section on small screens.
Copy this prompt to try it in V0
Subscription Billing with Stored Cards
Tokenize a customer's card during the first payment so future subscription charges can be processed without the customer re-entering their details. Adyen's recurring payment tokens (storedPaymentMethodId) let you charge customers on a schedule from your API route without any frontend interaction.
Build a subscription sign-up page with three plan cards (Basic, Pro, Enterprise) showing price, features, and a 'Get Started' button for each. When a plan is selected, show a payment section below the cards with the selected plan highlighted. The payment section should mount an Adyen card component that collects card details. Add a checkbox labeled 'Save card for future billing' checked by default.
Copy this prompt to try it in V0
Marketplace Split Payments
If you are building a marketplace where sellers receive a portion of each payment, Adyen Marketplace (formerly Adyen for Platforms) lets you split payments between your platform account and seller sub-accounts in a single API call. Build the seller payout dashboard and payment flow in V0.
Create a marketplace product page showing a product listing with seller info, price, and reviews. Include an 'Add to Cart' button and a checkout panel that shows the item price, platform fee breakdown, and total. Mount an Adyen Drop-in payment form in the checkout panel. After purchase, show an order confirmation with estimated delivery and seller contact details.
Copy this prompt to try it in V0
Troubleshooting
Drop-in container stays empty or shows 'Error occurred. Try again.' immediately on mount
Cause: The session creation API call failed, the client key or environment is incorrect, or the Adyen CSS was not imported so the Drop-in renders invisibly into a zero-height container.
Solution: Check the browser console and Network tab for the /api/adyen/session request. A 401 or 403 usually means the API key is invalid or the merchant account name is wrong. Confirm your NEXT_PUBLIC_ADYEN_CLIENT_KEY matches the client key in your Customer Area → API credentials. Verify the Adyen CSS is imported in globals.css.
TypeError: Cannot read properties of undefined reading 'sessions' or 'PaymentsApi'
Cause: The @adyen/api-library package changed its API surface between versions. The CheckoutAPI method path (checkout.sessions() vs checkout.PaymentsApi.sessions()) depends on the version installed.
Solution: Check your installed version with npm list @adyen/api-library. For v15+, use checkout.PaymentsApi.sessions(). For v14 and below, use checkout.sessions(). Pin to a specific version in package.json to avoid future breaking changes.
1// For @adyen/api-library v15+:2const response = await checkout.PaymentsApi.sessions(request);34// For @adyen/api-library v14 and below:5const response = await checkout.sessions(request);6// (or checkout.PaymentSessionsApi.sessions() depending on sub-version)Payment completes in the browser but onPaymentCompleted is never called — user stays on the checkout page
Cause: Some payment methods (like bank redirects or 3DS2 challenges) redirect the user away from your page and return via the returnUrl. The onPaymentCompleted callback only fires for non-redirect flows. Redirect-based flows deliver the result as query parameters on the returnUrl page.
Solution: Read the Adyen result from URL query parameters on your confirmation page. Adyen appends sessionId, sessionResult, and redirectResult to the returnUrl. Pass these to AdyenCheckout.submitDetails() on the confirmation page to finalize the payment and get the resultCode.
1// app/checkout/confirmation/page.tsx2'use client';3import { useSearchParams } from 'next/navigation';4import { useEffect, useState } from 'react';56export default function ConfirmationPage() {7 const params = useSearchParams();8 const resultCode = params.get('resultCode') ?? params.get('sessionResult');9 // Adyen sets resultCode=Authorised for non-redirect flows10 // and sessionResult for redirect flows (need to call submitDetails)11 return (12 <div>13 {resultCode === 'Authorised' ? 'Payment successful!' : `Status: ${resultCode}`}14 </div>15 );16}CORS error when the browser tries to reach checkoutshopper-live.adyen.com or checkoutshopper-test.adyen.com
Cause: Your allowed origin domains in the Adyen Customer Area do not include your Vercel deployment URL. Adyen validates the Origin header of browser requests against a whitelist of allowed domains set in your account.
Solution: In Adyen Customer Area, go to Developers → API credentials → your credential → Allowed origins and add your Vercel domain (e.g., https://your-app.vercel.app and https://your-app.vercel.app for preview deployments). Also add http://localhost:3000 for local development.
Best practices
- Always create a unique order reference (UUID) before calling the Adyen sessions endpoint — Adyen uses this reference to match webhook notifications to your orders and for reconciliation reports
- Store the sessionId alongside your order record in the database immediately after creating the session, even before payment completes — this lets you look up payment status later if the user closes the tab mid-payment
- Set up Adyen webhooks (Customer Area → Developers → Webhooks) to receive authorisation notifications server-side — never trust only the onPaymentCompleted client callback for order fulfillment, as users can close the tab before it fires
- Use Adyen's test card numbers (4111 1111 1111 1111 for Visa, 5500 0000 0000 0004 for Mastercard) and test scenarios from the Adyen test card documentation to verify your error and decline handling before going live
- Validate the amount server-side in your API route against your actual order total from the database — never trust the amount sent from the browser, which a user could manipulate
- Keep your ADYEN_API_KEY strictly server-side with no NEXT_PUBLIC_ prefix — an exposed API key allows anyone to create refunds, pull transaction reports, or create fraudulent sessions on your merchant account
- Always call dropin.unmount() in the React useEffect cleanup to prevent 'Target already occupied' errors and memory leaks when the component is unmounted or the page re-renders
Alternatives
Stripe offers instant sign-up and lower integration complexity — choose Stripe for most new projects unless you specifically need Adyen's enterprise features or global payment method coverage.
Square is better suited for businesses with both online and in-person payments that want unified reporting across point-of-sale and e-commerce transactions.
Authorize.net is a good choice for US-focused merchants already using the Visa/Mastercard network who want a mature, widely-supported gateway without Adyen's enterprise minimums.
Frequently asked questions
Do I need a special contract to use Adyen?
Yes. Unlike Stripe, Adyen does not offer instant self-serve sign-up for live processing. You apply for a merchant account, and an Adyen account manager reviews your business before activating live payments. Test accounts at ca-test.adyen.com are available immediately and free to use for development and testing without any approval process.
What is the difference between Adyen Drop-in and Adyen Components?
Drop-in is a ready-made payment form that includes a payment method selector, all available payment forms, and the entire flow in a single mount() call — it is the fastest way to get a full payment UI working. Components are individual UI elements (AdyenCard, AdyenPayPal, AdyenApplePay) that you mount separately and arrange yourself for a fully custom checkout layout. Drop-in is recommended for most use cases.
Why does the Adyen Drop-in load from checkoutshopper-live.adyen.com?
The Adyen Web SDK loads additional resources (payment method icons, locale files, 3DS frames) from Adyen's CDN at checkoutshopper-live.adyen.com (or checkoutshopper-test.adyen.com in test mode). This is expected and necessary — it is not a configuration error. Make sure your Content Security Policy headers allow connections to *.adyen.com if you have CSP rules configured in your Next.js app.
How do I handle the 3DS2 redirect in Next.js?
The Adyen Drop-in handles 3DS2 automatically within the component for most cases using an iframe. For payment methods that require a full-page redirect, Adyen will redirect to the returnUrl you set when creating the session. On the returnUrl page, read the redirectResult query parameter and call AdyenCheckout.submitDetails() to get the final payment result. The Drop-in handles this redirect reconciliation automatically if you mount it on the returnUrl page with the same session data.
Can I use the Adyen Web SDK in V0's preview environment?
V0's preview sandbox runs in an iframe, which can interfere with popup-based payment methods like Apple Pay and 3DS2 challenges. The Drop-in will render correctly in the preview, but redirect-based flows may not complete. Always test the full payment flow in your deployed Vercel app rather than in the V0 editor preview.
What test card numbers can I use with Adyen?
Adyen's primary test cards: Visa 4111 1111 1111 1111, Mastercard 5500 0000 0000 0004, Amex 3714 496353 98431. Use any future expiry date, any 3-digit CVC, and any name. To simulate declines, use specific card numbers from Adyen's documentation at docs.adyen.com/development-resources/testing/test-card-numbers — there are specific numbers for insufficient funds, expired card, and 3DS2 scenarios.
How do I process refunds with Adyen?
Refunds are initiated server-side by calling the Adyen Modifications API with the original payment's pspReference (the Adyen payment ID you receive in the webhook notification after authorization). In your Next.js API route, use checkout.ModificationsApi.refundCapturedPayment() from @adyen/api-library with the pspReference, amount, and merchant account. Adyen processes refunds asynchronously and sends a webhook notification when the refund is completed.
Talk to an Expert
Our team has built 600+ apps. Get personalized help with your project.
Book a free consultation