Search

Are you looking for test card numbers?

Would you like to contact support?

Online-payment icon

Web Drop-in integration guide

Accept popular payment methods with a single front-end implementation.

Try it out!

Visit our demo webshop. To see which payment methods are available in a country, select the country at the bottom of the page.

  For code samples, see our GitHub repository and other sample projects.

Drop-in is our all-in-one UI solution for accepting payments on your website using a single front-end implementation. Use Drop-in if you want a quick way to start accepting payments on your website, with little to no customization.

Drop-in is also available on iOS and Android. For an overview of all integration options and available features, refer to Online payments.

Supported payment methods

Drop-in readily supports cards, wallets, and most local payment methods. For a list of supported payment methods, refer to Supported payment methods.

Adding new payment methods usually requires no additional implementation effort, however some payment methods require additional configuration. For more information, refer to our payment method integration guides.

We're actively adding payment methods to Drop-in. To check the latest on Drop-in, see our release notes.

How it works

The following flow applies for each payment method supported in Drop-in:

On this page we describe both server-side and client-side integration steps:

  1. From your server, submit a request to get a list of payment methods available to the shopper.
  2. Create an instance of Drop-in on your payments form.
  3. From your server, submit a payment request with data you receive from Drop-in.
  4. Determine from the response if you need to perform additional actions on your front end.
  5. From your server, submit additional payment details with data you receive from Drop-in.
  6. Present the payment result to the shopper.

When you have completed the integration, proceed to test your integration.

Before you begin

If you haven't done so already, follow our Get started guide to set up your test account, get your API key, and install a server-side library.

To make sure that your 3D Secure integration works on Chrome, your cookies need to have the SameSite attribute. For more information, refer to Chrome SameSite Cookie policy.

Step 1: Get available payment methods

When your shopper is ready to pay, get a list of the available payment methods based on their country, device, and the payment amount.

From your server, make a POST /paymentMethods request, specifying:

Parameter name Required Description
merchantAccount -white_check_mark- Your merchant account name.
amount The currency and value of the payment, in minor units. This is used to filter the list of available payment methods to your shopper.
channel The platform of the shopper's device; use Web. This is used to filter the list of available payment methods to your shopper.
countryCode The shopper's country code. This is used to filter the list of available payment methods to your shopper.
shopperLocale By default, the shopperlocale is set to en-US. To change the language, set this to the shopper's language and country code. You also need to set the same locale within your Drop-in configuration.

Here's an example of how you would get the available payment methods for a shopper in the Netherlands, for a payment of 10 EUR:

curl https://checkout-test.adyen.com/v64/paymentMethods \
-H "x-API-key: YOUR_X-API-KEY" \
-H "content-type: application/json" \
-d '{
  "merchantAccount": "YOUR_MERCHANT_ACCOUNT",
  "countryCode": "NL",
  "amount": {
    "currency": "EUR",
    "value": 1000
  },
  "channel": "Web",
  "shopperLocale": "nl-NL"
}'
require 'adyen-ruby-api-library'

# Set your X-API-KEY with the API key from the Customer Area.
adyen = Adyen::Client.new
adyen.env = :test
adyen.api_key = "YOUR_X-API-KEY"

response = adyen.checkout.payment_methods({ 
    :merchantAccount => 'YOUR_MERCHANT_ACCOUNT',
    :countryCode => 'NL',
    :shopperLocale => 'nl_NL',
    :amount => {
        :currency => 'EUR',
        :value => 1000
    },
    :channel => 'Web'
})
# Pass the response to your front end
// Set your X-API-KEY with the API key from the Customer Area.
String xApiKey = "YOUR_X-API-KEY";
Client client = new Client(xApiKey,Environment.TEST);
Checkout checkout = new Checkout(client);
PaymentMethodsRequest paymentMethodsRequest = new PaymentMethodsRequest();
paymentMethodsRequest.setMerchantAccount("YOUR_MERCHANT_ACCOUNT");
paymentMethodsRequest.setCountryCode("NL");
paymentMethodsRequest.setShopperLocale("nl-NL");
Amount amount = new Amount();
amount.setCurrency("EUR");
amount.setValue(1000L);
paymentMethodsRequest.setAmount(amount);
paymentMethodsRequest.setChannel(PaymentMethodsRequest.ChannelEnum.Web);
PaymentMethodsResponse paymentMethodsResponse = checkout.paymentMethods(paymentMethodsRequest);
// Pass the response to your front end
// Set your X-API-KEY with the API key from the Customer Area.
$client = new \Adyen\Client();
$client->setEnvironment(\Adyen\Environment::TEST);
$client->setXApiKey("YOUR_X-API-KEY");
$service = new \Adyen\Service\Checkout($client);

$params = array(
    "merchantAccount" => "YOUR_MERCHANT_ACCOUNT",
    "countryCode" => "NL",
    "shopperLocale" => "nl-NL",
    "amount" => array(
        "currency" => "EUR",
        "value" => 1000
    ),
    "channel" => "Web"
);
$result = $service->paymentMethods($params);

// Pass the response to your front end
# Set your X-API-KEY with the API key from the Customer Area.
adyen = Adyen.Adyen()
adyen.payment.client.platform = "test"
adyen.client.xapikey = 'YOUR_X-API-KEY'

request = {
    'merchantAccount': 'YOUR_MERCHANT_ACCOUNT',
    'countryCode': 'NL',
    'shopperLocale': 'nl-NL',
    'amount': {
        'value': 1000,
        'currency': 'EUR'
    },
    'channel': 'Web'
}
response = adyen.checkout.payment_methods(request)
# Pass the response to your front end
// Set your X-API-KEY with the API key from the Customer Area.
string apiKey = "YOUR_X-API-KEY";
var client = new Client (apiKey, Environment.Test);
var checkout = new Checkout(client);
var amount = new Adyen.Model.Checkout.Amount("EUR", 1000);
var paymentMethodsRequest = new Adyen.Model.Checkout.PaymentMethodsRequest(merchantAccount: "YOUR_MERCHANT_ACCOUNT")
{ 
    CountryCode = "NL",
    ShopperLocale = "nl-NL",
    Amount = amount,
    Channel = PaymentMethodsRequest.ChannelEnum.Web
};
var paymentMethodsResponse = checkout.PaymentMethods(paymentMethodsRequest);
// Pass the response to your front end
const {Client, Config, CheckoutAPI} = require('@adyen/api-library');
const config = new Config();
// Set your X-API-KEY with the API key from the Customer Area.
config.apiKey = '[YOUR_X-API-KEY]';
config.merchantAccount = '[YOUR_MERCHANT_ACCOUNT]';
const client = new Client({ config });
client.setEnvironment("TEST");
const checkout = new CheckoutAPI(client);
const paymentsResponse = checkout.paymentMethods({ 
    merchantAccount: config.merchantAccount,
    countryCode: "NL",
    shopperLocale: "nl-NL",
    amount: { currency: "EUR", value: 1000, },
    channel: "Web"
}).then(res => res);
// Pass the response to your front end
import (
    "github.com/adyen/adyen-go-api-library/v2/src/checkout"
    "github.com/adyen/adyen-go-api-library/v2/src/common"
    "github.com/adyen/adyen-go-api-library/v2/src/adyen"
)
// Set your X-API-KEY with the API key from the Customer Area.
client := adyen.NewClient(&common.Config{
    Environment: common.TestEnv,
    ApiKey:      "[YOUR_X-API-KEY]",
})
res, httpRes, err := client.Checkout.PaymentMethods(&checkout.PaymentMethodsRequest{
    MerchantAccount: "[YOUR_MERCHANT_ACCOUNT]",
    CountryCode: "NL",
    ShopperLocale: "nl-NL",
    Amount: checkout.Amount{
        Value:    1000,
        Currency: "EUR",
    },
    Channel: "Web",
})
// Pass the response to your front end

The response includes the list of available paymentMethods:

/paymentMethods response
 {
   "paymentMethods":[
    {
      "details":[...],
      "name":"Credit Card",
      "type":"scheme"
      ...
    },
    {
      "details":[...],
      "name":"SEPA Direct Debit",
      "type":"sepadirectdebit"
    },
    ...
    ]
 }

Pass the response to your front end. You'll use this in the next step to show which payment methods are available for the shopper.

Step 2: Add Drop-in to your payments form

Next, use Drop-in to show the available payment methods, and to collect payment details from your shopper.

  1. Include the following script in the <body> above any other JavaScript in your checkout page: 

    We recommend that you also validate the Subresource Integrity (SRI) hash, which we provide for our JavaScript and CSS files.

    <script src="https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/3.13.0/adyen.js"
    integrity="sha384-cMH19I9HPj31iL3b/lcBcpsqbieCGSLyNef+RzjS7g3h5DhP2BI6j68/ogKSQCAh"
    crossorigin="anonymous"></script>
    <!-- Adyen provides the SRI hash that you include as the integrity attribute. Refer to our release notes to get the SRI hash for the specific version. https://docs.adyen.com/checkout/release-notes -->
  2. Use the following CSS file:

    <link rel="stylesheet" href="https://checkoutshopper-test.adyen.com/checkoutshopper/sdk/3.13.0/adyen.css"
    integrity="sha384-AtxcD/Ax9ZRBLJ63s/bwCMrfe/mXWt4TF7F+Vltoxo0WgAwWjVNDsfyMAgY+9nBi"
    crossorigin="anonymous">
    <!-- Adyen provides the SRI hash that you include as the integrity attribute. Refer to our release notes to get the SRI hash for the specific version. https://docs.adyen.com/checkout/release-notes -->

    You can add your own styling by overriding the rules in this CSS file.

  3. Create a DOM element on your checkout page, placing it where you want Drop-in to be rendered on the page.

    <div id="dropin-container"></div>

    If you are using JavaScript frameworks such as Vue or React, make sure that you use references instead of selectors and that you don't re-render the DOM element.

  1. Create a configuration object with the following parameters:

    Parameter name Required Description
    paymentMethodsResponse -white_check_mark- The full /paymentMethods response returned in step 1.
    clientKey -white_check_mark- A public key linked to your web service user, used for client-side authentication.
    Web Drop-in versions before 3.10.1 use originKey instead. Find out how to migrate from using originKey to clientKey.
    locale -white_check_mark- The shopper's locale. This is used to set the language rendered in the UI. For a list of supported locales, see Language and localization.
    environment -white_check_mark- Use test. When you're ready to accept live payments, change the value to one of our live environments
    onSubmit -white_check_mark- Create an event handler, called when the shopper selects the Pay button.
    onAdditionalDetails -white_check_mark- Create an event handler, used for native 3D Secure 2, and for native QR code payment methods.
    paymentMethodsConfiguration Required or optional configuration for specific payment methods. For more information, refer to our payment method guides.
    const configuration = {
     paymentMethodsResponse: paymentMethodsResponse // The `/paymentMethods` response from the server.
     clientKey: "YOUR_CLIENT_KEY", // Web Drop-in versions before 3.10.1 use originKey instead of clientKey.
     locale: "en-US",
     environment: "test",
     onSubmit: (state, dropin) => {
         // Your function calling your server to make the `/payments` request
         makePayment(state.data)
           .then(response => {
             if (response.action) {
               // Drop-in handles the action object from the /payments response
               dropin.handleAction(response.action);
             } else {
               // Your function to show the final result to the shopper
               showFinalResult(response);
             }
           })
           .catch(error => {
             throw Error(error);
           });
       },
     onAdditionalDetails: (state, dropin) => {
       // Your function calling your server to make a `/payments/details` request
       makeDetailsCall(state.data)
         .then(response => {
           if (response.action) {
             // Drop-in handles the action object from the /payments response
             dropin.handleAction(response.action);
           } else {
             // Your function to show the final result to the shopper
             showFinalResult(response);
           }
         })
         .catch(error => {
           throw Error(error);
         });
     },
     paymentMethodsConfiguration: {
       card: { // Example optional configuration for Cards
         hasHolderName: true,
         holderNameRequired: true,
         enableStoreDetails: true,
         hideCVC: false, // Change this to true to hide the CVC field for stored cards
         name: 'Credit or debit card'
       }
     }
    };
  2. Use the configuration object to create an instance of AdyenCheckout. Then use the returned value to create and mount the instance of Drop-in:

    const checkout = new AdyenCheckout(configuration);
    const dropin = checkout.create('dropin').mount('#dropin-container');

    When the shopper selects the Pay button, Drop-in calls the onSubmit event, which contains a state.data. These are the shopper details that you need to make the payment.

  3. Pass the state.data to your server.

    Sample state from onSubmit event for a card payment
    {
     isValid: true,
     data: {
       paymentMethod: {
         type: "scheme",
         encryptedCardNumber: "adyenjs_0_1_18$k7s65M5V0KdPxTErhBIPoMPI8HlC..",
         encryptedExpiryMonth: "adyenjs_0_1_18$p2OZxW2XmwAA8C1Avxm3G9UB6e4..",
         encryptedExpiryYear: "adyenjs_0_1_18$CkCOLYZsdqpxGjrALWHj3QoGHqe+..",
         encryptedSecurityCode: "adyenjs_0_1_18$XUyMJyHebrra/TpSda9fha978+.."
         holderName: "S. Hopper"
       }
     }
    }

Configuring Drop-in

You can include the following additional configuration when instantiating Drop-in on your payments form:

Configuration object Description
amount Amount to be displayed on the Pay Button. It expects an object with the value and currency properties. For example, { value: 1000, currency: 'USD' }.
openFirstPaymentMethod When enabled, Drop-in opens the first payment method automatically on page load. Defaults to true.
openFirstStoredPaymentMethod When enabled, Drop-in opens the payment method with stored card details on page load. This option takes precedence over openFirstPaymentMethod. Defaults to true.
showStoredPaymentMethods Shows or hides payment methods with stored card details. Defaults to true.
showPaymentMethods Shows or hides regular payment methods, useful if you only want to show payment methods with stored card details. Defaults to true.
showPayButton Show or hides a Pay Button for each payment method. Defaults to true. The Pay button triggers the onSubmit event when payment details are valid.

If you want to disable the button and then trigger the submit flow on your own, set this to false and call the .submit() method from your own button implementation. For example, dropin.submit()

Events

Use the following events to include additional logic on your checkout page:

Event name Description
onSubmit(state, dropin) Called when the shopper selects the Pay button and payment details are valid.
onAdditionalDetails(state, dropin) Called when a payment method requires more details.
onError(error) Called when an error occurs in Drop-in.
onReady() Called when Drop-in is initialized and is ready for use.
onSelect(component) Called when the shopper selects a payment method.

Step 3: Make a payment

After the shopper selects the Pay button or chooses to pay with a payment method that requires a redirection, you need to make a payment request to Adyen.

From your server, make a POST /payments request specifying:

Parameter name Required Description
merchantAccount -white_check_mark- Your merchant account name.
amount -white_check_mark- The currency and value of the payment (in minor units). For more information, see Currency codes.
reference -white_check_mark- Your unique reference for this payment.
paymentMethod -white_check_mark- The state.data.paymentMethod from the onSubmit event from your front end.
returnUrl -white_check_mark- URL to where the shopper should be taken back to after a redirection. The URL can contain a maximum of 1024 characters and should include the protocol: http:// or https://. You can also include your own additional query parameters, for example, shopper ID or order reference number.
applicationInfo If you're building an Adyen solution for multiple merchants, include some basic identifying information, so that we can offer you better support. For more information, refer to Building Adyen solutions.

You need to include additional parameters in your payment request to:

Here's an example of how you would make a payment request for 10 EUR:

curl https://checkout-test.adyen.com/v64/payments \
-H "x-API-key: YOUR_X-API-KEY" \
-H "content-type: application/json" \
-d '{
  "amount":{
    "currency":"EUR",
    "value":1000
  },
  "reference":"YOUR_ORDER_NUMBER",
  "paymentMethod":{hint:paymentMethod field of an object passed from the front end or client app}STATE_DATA{/hint},
  "returnUrl":"https://your-company.com/checkout?shopperOrder=12xy..",
  "merchantAccount":"YOUR_MERCHANT_ACCOUNT"
}'
require 'adyen-ruby-api-library'

# Set your X-API-KEY with the API key from the Customer Area.
adyen = Adyen::Client.new
adyen.env = :test
adyen.api_key = "YOUR_X-API-KEY"

# STATE_DATA is the paymentMethod field of an object passed from the front end or client app, deserialized from JSON to a data structure.
paymentMethod = STATE_DATA

response = adyen.checkout.payments({ 
    :merchantAccount => 'YOUR_MERCHANT_ACCOUNT',
    :paymentMethod => paymentMethod,
    :amount => {
        :currency => 'EUR',
        :value => 1000
    },
    :reference => "YOUR_ORDER_NUMBER",
    :returnUrl => "https://your-company.com/checkout?shopperOrder=12xy.."
})

# Check if further action is needed.
if response.body.has_key(:action)
   # Pass the action object to your front end
   # response.body[:action]
else
   # No further action needed, pass the resultCode object to your front end
   # response.body[:resultCode]
// Set your X-API-KEY with the API key from the Customer Area.
String xApiKey = "YOUR_X-API-KEY";
Client client = new Client(xApiKey,Environment.TEST);
Checkout checkout = new Checkout(client);
PaymentsRequest paymentsRequest = new PaymentsRequest();
paymentsRequest.setMerchantAccount("YOUR_MERCHANT_ACCOUNT");
// STATE_DATA is the paymentMethod field of an object passed from the front end or client app, deserialized from JSON to a data structure.
paymentsRequest.setPaymentMethod(STATE_DATA)
Amount amount = new Amount();
amount.setCurrency("EUR");
amount.setValue(1000L);
paymentsRequest.setAmount(amount);
paymentsRequest.setReference("YOUR_ORDER_NUMBER");
paymentsRequest.setReturnUrl("https://your-company.com/checkout?shopperOrder=12xy..");
PaymentsResponse paymentsResponse = checkout.payments(paymentsRequest);
// Set your X-API-KEY with the API key from the Customer Area.
$client = new \Adyen\Client();
$client->setEnvironment(\Adyen\Environment::TEST);
$client->setXApiKey("YOUR_X-API-KEY");
$service = new \Adyen\Service\Checkout($client);

// STATE_DATA is the paymentMethod field of an object passed from the front end or client app, deserialized from JSON to a data structure.
$paymentMethod = STATE_DATA;

$params = array(
    "merchantAccount" => "YOUR_MERCHANT_ACCOUNT",
    "paymentMethod" => $paymentMethod,
    "amount" => array(
        "currency" => "EUR",
        "value" => 1000
    ),
    "reference" => "YOUR_ORDER_NUMBER",
    "returnUrl" => "https://your-company.com/checkout?shopperOrder=12xy.."
);
$result = $service->payments($params);

// Check if further action is needed
if (array_key_exists("action", $result){
   // Pass the action object to your front end
   // $result["action"]
}
else {
   // No further action needed, pass the resultCode to your front end
   // $result['resultCode']
}
# Set your X-API-KEY with the API key from the Customer Area.
adyen = Adyen.Adyen()
adyen.payment.client.platform = "test"
adyen.client.xapikey = 'YOUR_X-API-KEY'

# STATE_DATA is the paymentMethod field of an object passed from the front end or client app, deserialized from JSON to a data structure.
paymentMethod = STATE_DATA

result = adyen.checkout.payments({
    'merchantAccount': 'YOUR_MERCHANT_ACCOUNT',
    'paymentMethod': paymentMethod,
    'amount': {
        'value': 1000,
        'currency': 'EUR'
    },
    'reference': 'YOUR_ORDER_NUMBER',
    'returnUrl': 'https://your-company.com/checkout?shopperOrder=12xy..'
})

# Check if further action is needed
if 'action' in result.message:
   # Pass the action object to your front end
   # result.message['action']
else:
   # No further action needed, pass the resultCode to your front end
   # result.message['resultCode']
// Set your X-API-KEY with the API key from the Customer Area.
string apiKey = "YOUR_X-API-KEY";
var client = new Client (apiKey, Environment.Test);
var checkout = new Checkout(client);
var amount = new Adyen.Model.Checkout.Amount("EUR", 1000);
var paymentRequest = new Adyen.Model.Checkout.PaymentRequest
{ 
// STATE_DATA is the paymentMethod field of an object passed from the front end or client app, deserialized from JSON to a data structure.
    PaymentMethod = STATE_DATA,
    Amount = amount,
    Reference = "YOUR_ORDER_NUMBER",
    ReturnUrl = @"https://your-company.com/checkout?shopperOrder=12xy.."
};
var paymentResponse = checkout.Payment(paymentRequest);
const {Client, Config, CheckoutAPI} = require('@adyen/api-library');
const config = new Config();
// Set your X-API-KEY with the API key from the Customer Area.
config.apiKey = '[YOUR_X-API-KEY]';
config.merchantAccount = '[YOUR_MERCHANT_ACCOUNT]';
const client = new Client({ config });
client.setEnvironment("TEST");
const checkout = new CheckoutAPI(client);
checkout.payments({ 
    merchantAccount: config.merchantAccount,
// STATE_DATA is the paymentMethod field of an object passed from the front end or client app, deserialized from JSON to a data structure.
    paymentMethod: STATE_DATA,
    amount: { currency: "EUR", value: 1000, },
    reference: "YOUR_ORDER_NUMBER",
    returnUrl: "https://your-company.com/checkout?shopperOrder=12xy.."
}).then(res => res);
import (
    "github.com/adyen/adyen-go-api-library/v2/src/checkout"
    "github.com/adyen/adyen-go-api-library/v2/src/common"
    "github.com/adyen/adyen-go-api-library/v2/src/adyen"
)
// Set your X-API-KEY with the API key from the Customer Area.
client := adyen.NewClient(&common.Config{
    Environment: common.TestEnv,
    ApiKey:      "[YOUR_X-API-KEY]",
})
// STATE_DATA is the paymentMethod field of an object passed from the front end or client app, deserialized from JSON to a data structure.
paymentMethod := STATE_DATA
res, httpRes, err := client.Checkout.Payments(&checkout.PaymentRequest{
    MerchantAccount: "[YOUR_MERCHANT_ACCOUNT]",
    PaymentMethod: paymentMethod,
    Amount: checkout.Amount{
        Value:    1000,
        Currency: "EUR",
    },
    Reference: "YOUR_ORDER_NUMBER",
    ReturnUrl: "https://your-company.com/checkout?shopperOrder=12xy..",
})

Your next steps depend on whether the /payments response contains an action object:

Description Next steps
no action object No additional steps are needed to complete the payment. Use the resultCode to present the payment result to your shopper.
With action object and action.type redirect The shopper is redirected to another website or app to complete the payment. 1. Check the /payments response to know what parameters to expect when the shopper returns to your website.
2. Store the action.paymentData in your server. You'll need this in your next API request.
3. Pass the action object to your front end. Drop-in uses this to handle the required action.
4. Proceed to step 4.
With action object The shopper needs to do additional actions to complete the payment. 1. Pass the action object to your front end. Drop-in uses this to handle the required action.
2. Proceed to step 4.

The following example shows a /payments response with action.type: threeDS2Fingerprint:

/payments response
{
   "resultCode":"IdentifyShopper",
   "action":{
     "paymentData":"Ab02b4c0!BQABAgCuZFJrQOjSsl\/zt+...",
     "paymentMethodType":"scheme",
     "token":"eyJ0aHJlZURTTWV0aG9kTm90aWZpY...",
     "type":"threeDS2Fingerprint"
   },
   "authentication":{
     "threeds2.fingerprintToken":"eyJ0aHJlZURTTWV0aG9kTm90aWZpY..."
   },
   "details":[
     {
       "key":"threeds2.fingerprint",
       "type":"text"
     }
   ],
   ...
}

Step 4: Perform additional front-end actions

Some payment methods require additional action from the shopper such as: to scan a QR code, to authenticate a payment with 3D Secure, or to log in to their bank's website to complete the payment.

To handle these additional front-end actions, Drop-in uses the dropin.handleAction function depending on the action.type. You should also use the action.type to determine your next steps.

action.type Description Next steps
voucher Drop-in displays the voucher which the shopper
uses to complete the payment.
1. Proceed to step 6 and inform the shopper that you are waiting for the payment.
2. Wait for the notification webhook to know the payment result.
redirect Drop-in redirects the shopper to another website or app
to complete the payment.
1. When the shopper returns to your website, your server needs to handle the redirect result.
2. Proceed to step 5 to check the payment result.
qrCode Drop-in presents the QR code
and calls the onAdditionalDetails event.
1. Get the state.data from the onAdditionalDetails event and pass it your server.
2. Proceed to step 5 to check the payment result.
await Drop-in shows the waiting screen while the shopper completes the payment.
Depending on the payment outcome, Drop-in calls the onAdditionalDetails or onError event.
1. Get the state.data object from the onAdditionalDetails or onError event and pass it your server.
2. Proceed to step 5 to check the payment result.
sdk Drop-in presents the specific payment method's UI as an overlay
and calls the onAdditionalDetails event.
1. Get the state.data from the onAdditionalDetails event and pass it your server.
2. Proceed to step 5 to check the payment result.
threeDS2Fingerprint The payment qualifies for 3D Secure 2, and will go through either the frictionless or the challenge flow.
Drop-in performs the authentication flow, and calls the onAdditionalDetails event.
1. Get the state.data from the onAdditionalDetails event and pass it your server.
3. Proceed to step 5 to complete the payment.
threeDS2Challenge The payment qualifies for 3D Secure 2, and the issuer is initiating a challenge flow.
Drop-in performs the authentication flow, and calls the onAdditionalDetails event.
1. Get the state.data from the onAdditionalDetails event and pass it your server.
3. Proceed to step 5 to complete the payment.

Handle the redirect result

If you receive an action.type redirect, Drop-in redirects your shopper to another website using an HTTP GET or HTTP POST request. The shopper will be redirected back to your returnURL using the same method.

The redirect method depends on your payment method configuration and the length of the data included in the request, so make sure that your integration can handle both HTTP GET and HTTP POST methods.

What parameters to expect

To know what parameters to expect when the shopper is redirected back to your website, get the redirect information from the action object in the /payments response.

  • details: Array that contains the key parameter names and the corresponding data type. If other parameters are appended to the returnURL or sent in the form data but are not included in the details object, ignore them. These are also the parameters that you will need to submit in a /payments/details request.
  • method: The HTTP request method used to redirect the shopper to your returnURL.

For example, you might receive the following response:

/payments response
{
  "resultCode": "RedirectShopper",
  "action": {
    "method": "GET",
    "paymentData": "Ab02b4c0!B..=",
    "paymentMethodType": "ideal",
    "type": "redirect",
    "url": "https://test.adyen.com/hpp/redirectIdeal.shtml?brandCode=ideal&currencyCode=EUR..."
    },
  "details": [
    {
      "key": "payload",
      "type": "text"
    }
  ]
  ...
}

If a shopper completed the payment but failed to return to your website, wait for the notification webhook to know the payment result.

Redirect methods

The redirect method depends on your payment method configuration and the length of the data included in the request, so make sure that your integration can handle both HTTP GET and HTTP POST methods.

HTTP GET redirect

After the shopper is redirected back to your returnURL with an HTTP GET, you need to:

  1. URL-decode the parameters appended to your returnURL and pass the parameters to your back end. Example parameters that you might get are payload or redirectResult.

    To know which parameters you should expect to be appended to the returnURL, check the details.key returned in the /payments response.

    For example, a shopper can be redirected back to your website with a payload parameter:

    GET /?shopperOrder=12xy..&&payload=Ab02b4c0!BQABF... HTTP/1.1
    Host: www.your-company.com/checkout
  2. Proceed to step 5.

HTTP POST redirect

After the shopper is redirected back to your returnURL with an HTTP POST, you need to:

  1. URL-decode the parameters from the form data and pass the parameters to your back end. To know which parameters you should expect in the form data, check the details.key returned in the /payments response.

    For example, MD and PaRes parameters are returned after a 3D Secure authentication.

    POST / HTTP/1.1
    Host: www.your-company.com/checkout?shopperOrder=12xy..
    Content-Type: application/x-www-form-urlencoded
    MD=dXlER3BhTEVCazlLd1..&PaRes=eNrNV0mTo7gS..
  2. Proceed to step 5.

Step 5: Submit additional payment details

If the shopper performed additional action, you need to make a /payments/details request to either complete the payment, or to check the payment result.

  • For action.type: redirect, pass in your request:

    • details: The parameters you received when the shopper was redirected back to your website.
    • paymentData: The value from the /payments response that you stored in your server.
  • For action.type: qrCode, await, sdk, threeDS2Fingerprint, or threeDS2Challenge, pass in your request the state.data from the onAdditionalDetails event.

The example below shows how you would submit additional payment details in case you received an onAdditionalDetails event.

curl https://checkout-test.adyen.com/v64/payments/details \
-H "x-API-key: YOUR_X-API-KEY" \
-H "content-type: application/json" \
-d '{hint:object passed from the front end or client app}STATE_DATA{/hint}'
require 'adyen-ruby-api-library'

# Set your X-API-KEY with the API key from the Customer Area.
adyen = Adyen::Client.new
adyen.env = :test
adyen.api_key = "YOUR_X-API-KEY"

# STATE_DATA is an object passed from the front end or client app, deserialized from JSON to a data structure.
request = STATE_DATA 
response = adyen.checkout.payments.details(request)  

# Check if further action is needed.
if response.body.has_key(:action)
   # Pass the action object to your frontend
   puts response.body[:action]
else
   # No further action needed, pass the resultCode to your frontend
   puts response.body[:resultCode]
end
// Set your X-API-KEY with the API key from the Customer Area.
String xApiKey = "YOUR_X-API-KEY";
Client client = new Client(xApiKey,Environment.TEST);
Checkout checkout = new Checkout(client);
// STATE_DATA is an object passed from the front end or client app, deserialized from JSON to a data structure.
PaymentsDetailsRequest paymentsDetailsRequest = STATE_DATA;
PaymentsResponse paymentsDetailsResponse = checkout.paymentsDetails(paymentsDetailsRequest);
// Set your X-API-KEY with the API key from the Customer Area.
$client = new \Adyen\Client();
$client->setEnvironment(\Adyen\Environment::TEST);
$client->setXApiKey("YOUR_X-API-KEY");
$service = new \Adyen\Service\Checkout($client);

// STATE_DATA is an object passed from the front end or client app, deserialized from JSON to a data structure.
$params = STATE_DATA;
$result = $service->paymentsDetails($params);

// Check if further action is needed
if (array_key_exists("action", $result){
   // Pass the action object to your frontend.
   // $result["action"]
}
else {
   // No further action needed, pass the resultCode to your front end
   // $result['resultCode']
}
# Set your X-API-KEY with the API key from the Customer Area.
adyen = Adyen.Adyen()
adyen.payment.client.platform = "test"
adyen.client.xapikey = 'YOUR_X-API-KEY'

# STATE_DATA is an object passed from the front end or client app, deserialized from JSON to a data structure.
request = STATE_DATA
result = adyen.checkout.payments_details(request)

# Check if further action is needed.
if 'action' in result.message:
   # Pass the action object to your front end
   # result.message['action']
else:
   # No further action needed, pass the resultCode to your front end
   # result.message['resultCode']
// Set your X-API-KEY with the API key from the Customer Area.
string apiKey = "YOUR_X-API-KEY";
var client = new Client (apiKey, Environment.Test);
var checkout = new Checkout(client);
// STATE_DATA is an object passed from the front end or client app, deserialized from JSON to a data structure.
var paymentsDetailsRequest = STATE_DATA;
var paymentsDetailsResponse = checkout.PaymentsDetails(paymentsDetailsRequest);
const {Client, Config, CheckoutAPI} = require('@adyen/api-library');
const config = new Config();
// Set your X-API-KEY with the API key from the Customer Area.
config.apiKey = '[YOUR_X-API-KEY]';
const client = new Client({ config });
client.setEnvironment("TEST");
const checkout = new CheckoutAPI(client);
// STATE_DATA is an object passed from the front end or client app, deserialized from JSON to a data structure.
checkout.paymentsDetails(STATE_DATA).then(res => res);
import (
    "github.com/adyen/adyen-go-api-library/v2/src/checkout"
    "github.com/adyen/adyen-go-api-library/v2/src/common"
    "github.com/adyen/adyen-go-api-library/v2/src/adyen"
)
// Set your X-API-KEY with the API key from the Customer Area.
client := adyen.NewClient(&common.Config{
    Environment: common.TestEnv,
    ApiKey:      "[YOUR_X-API-KEY]",
})
// STATE_DATA is an object passed from the front end or client app, deserialized from JSON to a data structure.
req := STATE_DATA;
res, httpRes, err := client.Checkout.PaymentsDetails(&req)

Depending on the payment result, you receive a response containing:

  • resultCode: Provides information about the result of the request.
  • pspReference: Our unique identifier for the transaction.
  • action: If you receive this object, you need to perform step 4 again.

If the /payments/details response does not contain an action object, proceed to step 6 to present the payment result to your shopper.

Successful payment response
 {
   "pspReference": "88154795347618C",
   "resultCode": "Authorised"
 }
Refused response
 {
   "pspReference": "89783918347627F",
   "refusalReason": "Not enough balance",
   "resultCode": "Refused"
 }

Step 6: Present the payment result

After the shopper completes the payment and no further actions are required on the front end, use the resultCode to inform the shopper of the payment status.

resultCode Description Action to take
Authorised The payment was successful. Inform the shopper that the payment was successful.
Error Inform the shopper that there was an error processing their payment. You'll receive a refusalReason in the same response, indicating the cause of the error.
Pending The shopper has completed the payment but the final result is not yet known. Inform the shopper that you've received their order, and are waiting for the payment to be completed.
You will receive the final result of the payment in an AUTHORISATION notification.
PresentToShopper Present the voucher or the QR code to the shopper. For a voucher payment method, inform the shopper that you are waiting for their payment. You will receive the final result of the payment in an AUTHORISATION notification.

For a qrCode payment method, wait for the AUTHORISATION notification before presenting the payment result to the shopper.
Refused The payment was refused. Inform the shopper that the payment was refused. Ask the shopper to try the payment again using a different payment method or card.
Received For some payment methods, it can take some time before the final status of the payment is known. Inform the shopper that you've received their order, and are waiting for the payment to clear.
You will receive the final result of the payment in an AUTHORISATION notification.

For other possible resultCode values and recommended messages that you can present to your shopper, see Result codes.

Alternatively, you can use the dropin.setStatus to show a customized message. For example:

  // Show a success message
  dropin.setStatus('success');
  dropin.setStatus('success', { message: 'Payment successful!' });

  // Show an error message
  dropin.setStatus('error');
  dropin.setStatus('error', { message: 'Something went wrong.'});

  // Set a loading state
  dropin.setStatus('loading'); // start the loading state
  dropin.setStatus('ready'); // set back to the initial state

Managing payment methods

Sort payment methods

The list of payment methods shown by Drop-in is ordered by popularity, the most popular payment methods in the shopper's country appearing at the top.

If you want to present the payment methods in a different order:

  1. Log in to your Customer Area.
  2. Go to Account > Checkout.
    If Checkout does not appear in the Account menu, ask your Admin user to enable the Change payment methods user role for your user account.
  3. Select a Country. The list of payment methods you now see are in the order they will appear to shoppers in this country.
  4. Drag the payment methods into the order that you want them to appear.
  5. Select Submit at the bottom of the page.

Remove payment methods

This action deactivates payment methods for your merchant account. If you only want to limit the payment methods for specific transactions, send allowedPaymentMethods or blockedPaymentMethods in your /paymentMethods request instead.

To remove a payment method from the list shown by Drop-in, we recommend that you deactivate this payment method:

  1. Log in to your Customer Area.
  2. Go to Account > Payment methods.
  3. Select the check box next to the payment method that you want you disable.
  4. Select Deactivate at the bottom of the page.

Error handling

In case you encounter errors in your integration, refer to the following:

  • API error codes: If you receive a non-HTTP 200 response, use the errorCode to troubleshoot and modify your request.
  • Payment refusals: If you receive an HTTP 200 response with an Error or Refused resultCode, check the refusal reason and, if possible, modify your request.

Test and go live

Before going live, use our list of test cards and other payment methods to test your integration. We recommend testing each payment method that you intend to offer to your shoppers.

You can check the status of a test payment in your Customer Area, under TransactionsPayments.

When you are ready to go live, you need to:

  1. Apply for a live account.
  2. Assess your PCI DSS compliance by submitting the Self-Assessment Questionnaire-A.
  3. Configure your live account
  4. Submit a request to add payment methods in your live Customer Area .
  5. Switch from test to our live endpoints.
  6. Load Drop-in from one of our live environments closest to where your shoppers are. Set the environment configuration object to:

    • Europe: live
    • Australia: live-au
    • US: live-us

See also

Next steps