iOS Drop-in
Render a list of available payment methods anywhere in your app.
Supported payment methods
Cards, buy now pay later, wallets, and many more.
See all supported payment methods
Features
- Lowest development time to integrate payment methods
- UI styling customization for the list of payment methods
- Adding payment methods to the list requires no extra development time
- 3D Secure 2 support built in
Start integrating with iOS Drop-in
Choose your versionDrop-in is our pre-built UI solution for accepting payments in your app. Drop-in shows all payment methods as a list, in the same block. For the Advanced flow, your server makes API requests to the /paymentMethods, /payments, and /payments/details endpoints.
Requirements
Before you begin to integrate, make sure you have followed the Get started with Adyen guide to:
- Get an overview of the steps needed to accept live payments.
- Create your test account.
After you have created your test account:
- Get your API key.
- Get your client key.
- Set up webhooks to know the payment outcome.
Install the Adyen iOS client-side library
Choose how you want to install the Adyen iOS client-side library:
To install iOS Drop-in using Swift Package Manager, follow the Apple guide and specify:
- The repository URL as
https://github.com/Adyen/adyen-ios
- The version to be at least 3.8.0
Get your client key
You need a client key, a public key linked to your API credential, that the iOS Drop-in uses for client-side authentication.
- Log in to your Customer Area.
- Go to Developers > API credentials, and select the API credential for your integration, for example ws@Company.[YourCompanyAccount].
- Under Authentication, select Generate New Client Key.
- Select Save.
How it works
For a Drop-in integration, you must implement the following parts:
The parts of your integration work together to complete the payment flow:
- From your server, submit a request to get a list of payment methods available to the shopper.
- Create an instance of Drop-in.
- From your server, submit a payment request with the data returned by Drop-in.
- Determine from the response if you need to perform additional actions on your client app.
- From your server, submit additional payment details with the data returned by Drop-in.
- Get the payment outcome.
If you are integrating these parts separately, you can start at the corresponding part of this integration guide:
Install an API library
We provide server-side API libraries for several programming languages, available through common package managers, like Gradle and npm, for easier installation and version management. Our API libraries will save you development time, because they:
- Use an API version that is up to date.
- Have generated models to help you construct requests.
- Send the request to Adyen using their built-in HTTP client, so you do not have to create your own.
Try our example integration
Requirements
- Java 11 or later.
Installation
You can use Maven, adding this dependency to your project's POM.
<dependency> <groupId>com.adyen</groupId> <artifactId>adyen-java-api-library</artifactId> <version>LATEST_VERSION</version> </dependency>
You can find the latest version on GitHub. Alternatively, you can download the release on GitHub.
Setting up the client
Create a singleton resource that you use for the API requests to Adyen:
// Import the required classes. package com.adyen.service; import com.adyen.Client; import com.adyen.service.checkout.PaymentsApi; import com.adyen.model.checkout.Amount; import com.adyen.enums.Environment; import com.adyen.service.exception.ApiException; import java.io.IOException; public class Snippet { public Snippet() throws IOException, ApiException { // Set up the client and service. Client client = new Client("ADYEN_API_KEY", Environment.TEST); } }
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, providing the following parameters. While most parameters are optional, we recommend that you include them because Adyen uses these to tailor the list of payment methods for your shopper.
We use the optional parameters to tailor the list of available payment methods to your shopper.
Parameter name | Required | Description |
---|---|---|
merchantAccount |
![]() |
Your merchant account name. |
amount |
The currency of the payment and its value in minor units. |
|
channel |
The platform where the payment is taking place. Use iOS. Adyen returns only the payment methods available for iOS. | |
countryCode |
The shopper's country/region. Adyen returns only the payment methods available in this country. Format: the two-letter ISO-3166-1 alpha-2 country code. Exception: QZ (Kosovo). |
|
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 ShopperLocale within your Drop-in configuration. |
The following example shows how to get the available payment methods for a shopper in the Netherlands, for a payment of EUR 10:
curl https://checkout-test.adyen.com/checkout/v70/paymentMethods \ -H 'x-api-key: ADYEN_API_KEY' \ -H 'content-type: application/json' \ -d '{ "merchantAccount": "ADYEN_MERCHANT_ACCOUNT", "countryCode": "NL", "amount": { "currency": "EUR", "value": 1000 }, "channel": "Android", "shopperLocale": "nl-NL" }'
The response includes the list of available paymentMethods
:
{ "paymentMethods":[ { "details":[...], "name":"Cards", "type":"scheme" ... }, { "details":[...], "name":"SEPA Direct Debit", "type":"sepadirectdebit" }, ... ] }
Pass the response to your client app. You will use this in the next step to present which payment methods are available to the shopper.
Add Drop-in to your payment form
Next, use Drop-in to show the available payment methods and to collect payment details from your shopper.
-
Decode the /paymentMethods response with the
PaymentMethods
structure.Decode the /paymentMethods responseExpand viewCopy link to code blockCopy codelet paymentMethods = try JSONDecoder().decode(PaymentMethods.self, from: paymentMethodsResponse)
-
Create an instance of
APIContext
that contains to following:Description Client key Authenticates requests from your payment environment. Environment setting The environment value that matches the endpoint that your server uses. Use Environment.test for your test environment. Create the APIContextExpand viewCopy link to code blockCopy code// Set the client key and environment in an instance of APIContext. let apiContext = APIContext(clientKey: clientKey, environment: Environment.test) // Set the environment to a live one when going live. -
Create an instance of
AdyenContext
that contains the following:Description API context Your instance of APIContext
.Payment information A Payment
object with the payment amount and currency.Create the AdyenContextExpand viewCopy link to code blockCopy code// Create the amount with the value in minor units and the currency code. let amount = Amount(value: 1000, currencyCode: "EUR") // Create the payment object with the amount and country code. let payment = Payment(amount: amount, countryCode: "NL") // Create an instance of AdyenContext, passing the instance of APIContext, and payment object. let adyenContext = AdyenContext(apiContext: apiContext, payment:payment) -
Create a Drop-in configuration object (
DropInComponent.Configuration
). You can add the following:Type of configuration Description Payment method configuration Some payment methods require additional configuration or have optional configuration. Optional configuration You can add optional configuration for Drop-in. The following example shows an optional configuration for cards.
Configure Drop-inExpand viewCopy link to code blockCopy codelet dropInConfiguration = DropInComponent.Configuration() // Some payment methods have additional required or optional configuration. // For example, an optional configuration to show the cardholder name field for cards. dropInConfiguration.card.showsHolderNameField = true -
Initialize Drop-in (
DropInComponent
).Parameter name Required Description paymentMethods
The full, decoded /paymentMethods response. context
The AdyenContext
that you created.paymentMethodsConfiguration
For some payment methods. Configuration for specific payment methods. Initialize Drop-inExpand viewCopy link to code blockCopy codelet dropInComponent = DropInComponent(paymentMethods: paymentMethods, context: adyenContext, configuration: dropInConfiguration) // Keep the instance of Drop-in so that it doesn't get destroyed after the function is executed. self.dropInComponent = dropInComponent // Set self as the delegate. dropInComponent.delegate = self // If you support gift cards, set self as the partial payment delegate. dropInComponent.partialPaymentDelegate = self -
After the shopper selects a payment method and provides payment details, Drop-in invokes the
didSubmit
method. Get the contents ofdata.paymentMethod
and pass this to your server.func didSubmit(_ data: PaymentComponentData, for paymentMethod: PaymentMethod, from component: DropInComponent)
If an error occurs on the app, Drop-in invokes the
didFail
method. Dismiss Drop-in's view controller and display an error message.func didFail(with error: Error, from component: DropInComponent)
If the shopper decides not to continue with the selected payment method, Drop-in invokes the
didCancel
method. You can usedidCancel
to track the state of the payment.func didCancel(component: PaymentComponent, from dropInComponent: DropInComponent)
For more information on iOS Drop-in classes, see our reference documentation page.
Make a payment
After the shopper submits their payment details 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 |
![]() |
Your merchant account name. |
amount |
![]() |
The currency of the payment and its value in minor units. |
reference |
![]() |
Your unique reference for this payment. |
paymentMethod |
![]() |
The data.paymentMethod from the didSubmit method from your client app. |
returnUrl |
![]() |
The URL the shopper should be taken back to after a redirection. Use the custom URL for your app, for example, my-app://adyen , to take the shopper back to your app after they complete the payment outside of your app. For more information on setting a custom URL scheme, read the Apple Developer documentation. The URL can contain a maximum of 1024 characters. You can also include your own additional query parameters, for example, shopper ID or order reference number. |
applicationInfo
|
If you are 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:
- Integrate some payment methods. For more information, refer to our payment method integration guides.
- Make use of our risk management features. For more information, see Required risk fields.
- Use native 3D Secure 2 authentication.
- Tokenize your shopper's payment details or make recurring payments.
The following example shows how to make a payment request for EUR 10:
curl https://checkout-test.adyen.com/checkout/v70/payments \ -H 'x-api-key: ADYEN_API_KEY' \ -H 'content-type: application/json' \ -d '{ "amount":{ "currency":"EUR", "value":1000 }, "reference":"YOUR_ORDER_NUMBER", "paymentMethod":STATE_DATApaymentMethod field of an object passed from your client app, "returnUrl":"my-app://adyen", "merchantAccount":"ADYEN_MERCHANT_ACCOUNT" }'
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. | 1. Dismiss Drop-in. 2. Get the payment outcome. |
action object |
The shopper needs to do additional actions to complete the payment. | 1. Pass the action object to your client app. 2. Perform additional client-side actions. |
The following example shows a /payments response with action.type
: threeDS2Fingerprint:
{ "resultCode":"IdentifyShopper", "action":{ "paymentData":"Ab02b4c0!BQABAgCuZFJrQOjSsl\/zt+...", "paymentMethodType":"scheme", "token":"eyJ0aHJlZURTTWV0aG9kTm90aWZpY...", "type":"threeDS2Fingerprint" }, "authentication":{ "threeds2.fingerprintToken":"eyJ0aHJlZURTTWV0aG9kTm90aWZpY..." }, "details":[ { "key":"threeds2.fingerprint", "type":"text" } ], ... }
Handle the additional action
Some payment methods require additional action from the shopper such as: to authenticate a payment with 3D Secure, or to switch to another app to complete the payment.
To handle these additional client app actions, Drop-in uses the action
object from the previous step. You should also use the action.type
to determine your next steps.
-
Use
dropInComponent.handle(action)
to trigger Drop-in to perform additional actions.let action = try JSONDecoder().decode(Action.self, from: actionData) dropInComponent.handle(action) -
Drop-in performs additional client app actions depending on the
action.type
. Your next steps depend on the type of action that Drop-in performs.
action.type |
Description | Next steps |
---|---|---|
redirect | Drop-in redirects the shopper to another website or app to complete the payment. When the shopper is redirected back to your app, Drop-in calls the didProvide method. |
1. Get the data from the didProvide method and pass it to your server. Dismiss the dropInComponent immediately, or wait until you have submitted the details to your server. 2. When the shopper returns to your app, handle the redirect result. 3. Send additional payment details to check the payment result. |
threeDS2 | 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 didProvide method. |
1. Get the data from the didProvide method and pass it to your server. Dismiss the dropInComponent immediately, or wait until you have submitted the details to your server. 2. Send additional payment details to submit additional payment details. |
sdk | Drop-in triggers the app switch from your app to the payment method's app, if installed in the shopper's device. When the shopper is redirected back to your app, Drop-in calls the didProvide method. |
1. Get the data from the didProvide method and pass it to your server. Dismiss the dropInComponent immediately, or wait until you have submitted the details to your server. 2. Send additional payment details to check the payment result. |
voucher | Drop-in presents UI for voucher. The shopper expected to shared, save voucher as image or, in some cases, add voucher to AppleWallet. When shopper finishes the flow, Drop-in calls didComplete |
Dismiss the dropInComponent immediately. Payment flow is completed. |
await | Drop-in presents await UI. The shopper expected to continue payment process outside of the merchant's app. Drop-in will poll payment status and, if completed, calls the didProvide method. |
1. Get the data from the didProvide method and pass it to your server. Dismiss the dropInComponent immediately, or wait until you have submitted the details to your server. 2. Send additional payment details to submit additional payment details. |
qrCode | Drop-in presents UI for QR code payment. The shopper expected to continue payment process outside of the merchant's app. Drop-in performs the flow, and calls the didProvide method. |
1. Get the data from the didProvide method and pass it to your server. Dismiss the dropInComponent immediately, or wait until you have submitted the details to your server. 2. Send additional payment details to submit additional payment details. |
Handle the redirect result
If the Action
class returns .redirect
, the shopper is redirected to an external site or to another application to complete the payment. You then need to inform Drop-in when the shopper returns to your app. To do this, implement the following in your UIApplicationDelegate
:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey: Any] = [:]) -> Bool { RedirectComponent.applicationDidOpen(from: url) return true }
Send additional payment details
If the shopper performed additional action to complete the payment, you need to make another request to Adyen to either submit the additional payment details or to check the payment result.
-
Get the
data
from thedidProvide
method from your client app.func didProvide(_ data: ActionComponentData, from component: ActionComponent, in dropInComponent: AnyDropInComponent)
-
From your server, make a /payments/details request with the
Expand viewCopy link to code blockCopy codecurl https://checkout-test.adyen.com/checkout/v70/payments/details \ -H 'x-api-key: ADYEN_API_KEY' \ -H 'content-type: application/json' \ -d 'STATE_DATAobject passed from your client app' You get a response that includes the
resultCode
that you can use to inform the shopper.The following example shows a payment response for a successful payment.
Successful payment responseExpand viewCopy link to code blockCopy code{ "pspReference": "NC6HT9CRT65ZGN82", "resultCode": "Authorised" } The following example shows a response for a refused payment.
Refused responseExpand viewCopy link to code blockCopy code{ "pspReference": "KHQC5N7G84BLNK43", "refusalReason": "Not enough balance", "resultCode": "Refused" }
Dismiss Drop-in
After you make a /payments, or /payments/details request and submit the payment data and/or additional details, dismiss Drop-in to finalize the payment flow.
Call finalizeIfNeeded
and do the following, depending on what the Drop-in handled:
What to do | |
---|---|
Result code | If no further steps are required from the application, dismiss Drop-in. |
Error | Dismiss Drop-in, and show an error message. |
Implement the following in your dropInComponent
object:
dropInComponent?.finalizeIfNeeded(with: isSuccessful) { [weak self] in guard let self else { return } myCheckoutViewController.dismiss(animated: true) { [weak self] in // Continue the flow. } }
Get the payment outcome
After Drop-in finishes the payment flow, you can show the shopper the current payment status. Adyen sends a webhook with the outcome of the payment.
Inform the shopper
Use the
resultCode
to show the shopper the current payment status. This synchronous response doesn't give you the final outcome of the payment. You get the final payment status in a webhook that you use to update your order management system.
Update your order management system
You get the outcome of each payment asynchronously, in an AUTHORISATION webhook. Use the merchantReference
from the webhook to match it to your order reference.
For a successful payment, the event contains success
: true.
{ "live": "false", "notificationItems":[ { "NotificationRequestItem":{ "eventCode":"AUTHORISATION", "merchantAccountCode":"YOUR_MERCHANT_ACCOUNT", "reason":"033899:1111:03/2030", "amount":{ "currency":"EUR", "value":2500 }, "operations":["CANCEL","CAPTURE","REFUND"], "success":"true", "paymentMethod":"mc", "additionalData":{ "expiryDate":"03/2030", "authCode":"033899", "cardBin":"411111", "cardSummary":"1111" }, "merchantReference":"YOUR_REFERENCE", "pspReference":"NC6HT9CRT65ZGN82", "eventDate":"2021-09-13T14:10:22+02:00" } } ] }
For an unsuccessful payment, you get success
: false, and the reason
field has details about why the payment was unsuccessful.
{ "live": "false", "notificationItems":[ { "NotificationRequestItem":{ "eventCode":"AUTHORISATION", "merchantAccountCode":"YOUR_MERCHANT_ACCOUNT", "reason":"validation 101 Invalid card number", "amount":{ "currency":"EUR", "value":2500 }, "success":"false", "paymentMethod":"unknowncard", "additionalData":{ "expiryDate":"03/2030", "cardBin":"411111", "cardSummary":"1112" }, "merchantReference":"YOUR_REFERENCE", "pspReference":"KHQC5N7G84BLNK43", "eventDate":"2021-09-13T14:14:05+02:00" } } ] }
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 Transactions > Payments.
To debug or troubleshoot test payments, you can also use API logs in your test environment.
When you are ready to go live, you need to:
- Apply for a live account.
- Assess your PCI DSS compliance, and submit the Self-Assessment Questionnaire-A.
- Configure your live account.
- Switch from test to our live endpoints.
-
Load Drop-in from one of our live environments and set the
dropInComponent.environment
to match your live endpoints:Endpoint region environment
valueEurope liveEurope Australia liveAustralia US liveUnitedStates Asia Pacific and South East liveApse
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.
Optional configuration
You can set additional configuration on the Drop-in configuration.
Parameter name | Description |
---|---|
shopperInformation |
Prefilled shopper information. |
localizationParameters |
Localization parameters, like custom placeholders in other languages. |
style |
Custom styling of the UI. |
Localization
iOS Drop-in supports the languages listed here.
To customize a localization, add a new localizable.strings
file for the language that you need. You can also override existing strings by using the same keys.
For example, to override the cardholder name field title, set the following on your localizable.strings
file:
"adyen.card.nameItem.title" = "Your cardholder name";
To find localized strings, the library first checks your custom localizable.strings
file, and then the default Adyen file.
You can use LocalizationParameters
to customize the localization file name, bundle, or the separator for translation strings.
For example, if you store translations in MyLocalizable.strings
files in the shared bundle CommonBundle
:
let localizationParameters = LocalizationParameters(bundle: commonBundle, tableName: "MyLocalizable") dropInComponent.localizationParameters = localizationParameters











