---
title: "Two-step checkout"
description: "Add a payment review page in your checkout flow."
url: "https://docs.adyen.com/online-payments/two-step-checkout"
source_url: "https://docs.adyen.com/online-payments/two-step-checkout.md"
canonical: "https://docs.adyen.com/online-payments/two-step-checkout"
last_modified: "2026-06-01T15:33:14+02:00"
language: "en"
---

# Two-step checkout

Add a payment review page in your checkout flow.

[View source](/online-payments/two-step-checkout.md)

In a two-step checkout flow, you redirect your shoppers to an additional page before they pay. This lets your shoppers review their order and payment details after they have filled in their details in your checkout form before they pay. A review page can include details of the payment, shipping method and address, billing information, and other details related to the purchase.

## Requirements

Before you begin, take into account the following requirements, limitations, and preparations.

| Requirement                                                               | Description                                                                                                                                    |
| ------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| **Integration type**                                                      | Make sure that you have a [Web Components/Drop-in integration using the Advanced flow](/online-payments/build-your-integration/advanced-flow). |
| **[API credential roles](/development-resources/api-credentials/roles/)** | Make sure that your API credential has the **Checkout webservice role**.                                                                       |

## How it works

1. On your checkout page, collect the shopper's payment details, and show a custom button that redirects shoppers to an additional order review page.
2. When the shopper selects the button, store the payment data on your server, and redirect them to a page where they can review their payment and order details.
3. On the review page, show the information that you want to include, and a **Pay** button.
4. When the shopper selects **Pay**, make a [/payments](https://docs.adyen.com/api-explorer/Checkout/latest/post/payments) request using the payment data you stored.

## Modify your checkout page

A two-step checkout flow starts with the same steps as the standard checkout flow. You make a [/paymentMethods](https://docs.adyen.com/api-explorer/Checkout/latest/post/paymentMethods) request to [get the available payment methods](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Components\&version=latest#get-available-payment-methods), and present the payment methods and the checkout form with our Web [Drop-in](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Drop-in\&version=latest#add) or [Components](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Components#add\&version=latest).

After the shopper selects a payment method, modify your checkout page to implement a two-step checkout flow.

1. In your [Drop-in](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Drop-in\&version=latest#add) or [Components](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Components\&version=latest#add) `configuration` object, set `showPayButton` to **false** to hide the default **Pay** button.

   **Hide the default pay button**

   ```js
   const configuration = {
     clientKey: "YOUR_CLIENT_KEY",
     environment: "test",
     amount: {
       value: 1000,
       currency: 'EUR'
     },
     locale: 'nl-NL',
     countryCode: 'NL',
     // The full /paymentMethods response object from your server. Contains the payment methods configured in your account.
     paymentMethodsResponse: paymentMethodsResponse,
     showPayButton: false,
     // Your other configurations...
   }
   ```

   This hides the default **Pay** button that otherwise triggers the `onSubmit` event when payment details are valid, and makes a payment request.

   When configuring Drop-in/Components for cards, you can [configure optional events](#show-additional-information-for-cards) that let you show additional information on the review page later.

2. On the page where the shopper enters their payment details, show your custom button. Implement your button with a function to:

   1. Validate the shopper input in the payment form.

   2. Store the payment data on your server to use it in your [/payments](https://docs.adyen.com/api-explorer/Checkout/latest/post/payments) request later.

      * For **Drop-in**, store the `dropin.activePaymentMethod.data`.

      * For **Components**, store the `data` from the payment method component. For example, store `card.data` for the card component.

        The payment data expires after an hour. If you submit a payment request with it after it expires, the request fails. After the payment data expires, the shopper must repeat the checkout process from the beginning.

   3. Redirect the shopper to your review page.

   The following code sample uses the example function `handleGoToReview` for Drop-in.

   **Implement the custom function for Drop-in**

   ```js
   handleGoToReview() {
       // Validate the shopper input in the payment form.
       if (dropin.activePaymentMethod.isValid) {
          // Store the payment data to use in the /payments request.
          setPaymentData(dropin.activePaymentMethod.data);
          // Redirect your shopper to your review page.
          showReviewPage();
       } else {
          // If the payment method details are invalid, trigger the validation to focus on the missing field.
          dropin.activePaymentMethod.showValidation();
      }
   }
   ```

3. In your [Drop-in](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Drop-in\&version=latest#add) or [Components](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Components\&version=latest#add) `configuration` object, call your custom function from the `onEnterKeyPressed` callback.

   **Call your custom function**

   ```js
   const configuration = {
     // Your other Drop-in and Components configurations.
     showPayButton: false,
     onEnterKeyPressed: () => {
          this.handleGoToReview();
     }
   }
   ```

## Implement a review page

1. On the review page, create a new instance of checkout.

   * Only if you use [Web Drop-in v6 or later, and import Drop-in with individual payment methods](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Drop-in\&version=6.0.0#add), you need to register the payment methods used in the Drop-in.

     **Register the payment methods for Drop-in**

     ```js
     checkoutRef.current.register([Card]);
     ```

2. When the shopper selects the **Pay** button on your review page, make a [/payments](https://docs.adyen.com/api-explorer/Checkout/latest/post/payments) request. Use the payment data you stored.

3. Handle the [/payments](https://docs.adyen.com/api-explorer/Checkout/latest/post/payments) response. Implement logic to handle the response with and without the `action` object.

   | Response                | Description                                                         | Next steps                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
   | ----------------------- | ------------------------------------------------------------------- |   |
   | Without `action` object | No additional steps are needed to complete the payment.             | 1. Handle the final state. 2. Get the payment outcome with your [Components](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Components\&version=latest#get-the-payment-outcome) or [Drop-in](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Drop-in\&version=latest#get-the-payment-outcome) integration.                                                                                                                                                                                                                                                                                                                          |
   | With `action` object    | The shopper needs to do additional actions to complete the payment. | 1. Perform additional front-end actions with your [Drop-in](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Drop-in\&version=latest#additional-action) or [Components](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Components\&version=latest#additional-action) integration. 2. Get the payment outcome with your [Components](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Components\&version=latest#get-the-payment-outcome) or [Drop-in](/online-payments/build-your-integration/advanced-flow/?platform=Web\&integration=Drop-in\&version=latest#get-the-payment-outcome) integration. |

   **Handle the /payments response**

   ```js
   function handleResponse({ action, resultCode, pspReference }) {
       if (action) {
           checkout.createFromAction(action).mount('.payment-method');
       } else {
           handleFinalState(resultCode, pspReference);
       }
   }
   ```

## Show additional information for cards

For card payments, you can show additional information on the review page using [card component](/payment-methods/cards/web-component/#optional-configuration) events.

When configuring Drop-in/Components, you can optionally configure the following events that allow you to show additional information on the review page.

| Event          | Description                                                                                                                                                                                                                                                                       |
| -------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `onBrand`      | Called when Drop-in/Component detects the card brand. Use this event to show the card brand on your review page.                                                                                                                                                                  |
| `onFieldValid` | Called when the input in a field becomes valid and also if the input changes and becomes invalid. For the card number field, it returns the `endDigits` field that contains the last 4 digits of the card number. Use this event to show the card end digits on your review page. |

## See also

* [Advanced flow integration guide](/online-payments/build-your-integration/advanced-flow)
