The Payment Widget is an integrated tool that allows you to offer multiple payment methods to your customers.
This widget is compatible with both Alternative Payment Method (APMs) and credit and debit cards, providing flexibility in payment options for users.
The Payment Widget supports:
- Alternative Payment Methods (APMs): such as OXXO, KueskiPay, among others.
- Credit and Debit Cards: MasterCard, Visa, American Express, and so on.
Initialize the widget
Before integrating the Payment Widget, complete the First steps - iOS.
1. Show the widget
Show the widget. You can do it in two ways:
- In a modal
- Embedded (SwidtUI
Show in a modal
To show the Payment Widget in a modal (pageSheet), call the initPaymentWidget function passing the following data:
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
userToken: "<DEUNA user token>", // optional
styleFile: "<DEUNA theme ID to customize the look and feel of the widget>", // optional
callbacks: PaymentWidgetCallbacks(
onSuccess: { order in
self.deunaSDK.close() // Close the payment widget
},
onError: { error in
// Error handling
if(error.type == .paymentError){
// YOUR CODE HERE
}
},
onClosed: { action in
// Widget closed
},
onCardBinDetected: { metadata in
guard metadata != nil else {
// Your code here
}
}
),
)Show the widget embedded (SwiftUI)
Use the DeunaWidget view to show the payment widget embedded in your app with SwiftUI.
import DeunaSDK
import SwiftUI
struct YourView: View {
let deunaSDK: DeunaSDK
var body: some View {
VStack {
DeunaWidget(
deunaSDK: deunaSDK,
configuration: PaymentWidgetConfiguration(
orderToken: "YOUR_ORDER_TOKEN",
callbacks: PaymentWidgetCallbacks(
onSuccess: { order in
// NOTE: Explicitly release widget resources
// when no longer needed
// to prevent memory leaks and ensure proper cleanup.
deunaSDK.dispose()
},
onError: { error in
if(error.type == .paymentError){
// YOUR CODE HERE
}
},
onEventDispatch: { event, data in
}
)
)
)
}
}
}Parameters
Attributes | Modal | Embedded | Description |
|---|---|---|---|
| ✅ | ✅ | The orderToken is a unique token generated for the payment order. This token is generated through the DEUNA API and you must implement the corresponding endpoint in your backend to obtain this information.
|
| ✅ | ✅ | The DEUNA user's bearer token. When this is sent, all actions within the widget will be performed on this DEUNA user.
|
| ✅ | ✅ | Callbacks are return functions that listen to and handle payment widget events. These events allow managing specific actions based on the payment status. The main callbacks include: |
| ✅ | ✅ | UUID provided by DEUNA. This applies if you want to configure a custom |
| ✅ | ✅ | A list of allowed payment methods. This parameter determines what type of widget should be rendered. |
| ✅ | ✅ | This parameter allows specifying the language in which the widget interface will be displayed. It must be provided as a valid language code (for example, "es" for Spanish, "en" for English, "pt" for Portuguese). Behavior:
|
| ✅ | ✅ | Use this parameter to configure the widget's behavior. |
| ✅ | ✅ | This allows DEUNA to generate the fraudId and then send it to your anti-fraud provider. Check here for more info on how to configure this attribute |
IMPORTANT: Configuration for Voucher Downloads on iOS
On iOS, for payment methods that generate voucher or receipt downloads (for example, payments with OXXO PAY), additional configuration is necessary in your application.
You must add the NSPhotoLibraryUsageDescription key in the Info.plist file. This will allow your app to have the necessary permissions to download and store receipts on the user's device.
Example configuration in Info.plist:
<key>NSPhotoLibraryUsageDescription</key> <string>The application needs access to the gallery to download and store payment receipts.</string>
fraudCredentials Parameter (Optional)
The initPaymentWidget function and the PaymentWidgetConfiguration class accept the fraudCredentials parameter .
Example:
/// DIALOG
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
fraudCredentials: [
"RISKIFIED": [
"storeDomain": "deuna.com"
]
]
)
/// EMBEDDED
DeunaWidget(
deunaSDK: deunaSDK,
configuration: PaymentWidgetConfiguration(
orderToken: "YOUR_ORDER_TOKEN",
fraudCredentials: [
"RISKIFIED": [
"storeDomain": "deuna.com"
]
]
)
)behavior Parameter (Optional)
The initPaymentWidget function and PaymentWidgetConfiguration class accept the behavior parameter which must be an instance of the WidgetBehavior class that allows customizing the payment widget's behavior, including:
- Enabling payments with multiple cards.
- Among other configuration options.
Note: These configurations apply to all payment methods enabled in the widget.
Payment Methods Behavior paymentMethods
paymentMethodsThe paymentMethods parameter within behavior allows configuring global behaviors for all payment methods enabled in the widget.
- flowType (Flow Type)
- Values (string):
twoSteporsingleStep - Current compatibility: Exclusive for PayPal.
Controls the display flow for specific payment methods that require showing prior information before the payment form.
/// DIALOG
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
behavior: WidgetBehavior(
paymentMethods: [
"flowType" : "twoStep"
]
)
)
/// EMBEDDED
DeunaWidget(
deunaSDK: deunaSDK,
configuration: PaymentWidgetConfiguration(
orderToken: "YOUR_ORDER_TOKEN",
behavior: WidgetBehavior(
paymentMethods: [
"flowType" : "twoStep"
]
)
)
)Split Payment with Multiple Cards (Split Payments)
The Split Payments feature allows customers to split a purchase payment between multiple credit/debit cards.
Requirements
- The option must be enabled in the merchant configuration.
- Currently only splitting between 2 cards maximum is supported.
/// MODAL
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
behavior: WidgetBehavior(
paymentMethods: [
"creditCard": [
"splitPayments": [
"maxCards": 2
]
]
]
)
)
// EMBEDDED
DeunaWidget(
deunaSDK: deunaSDK,
configuration: PaymentWidgetConfiguration(
orderToken: "YOUR_ORDER_TOKEN",
behavior: WidgetBehavior(
paymentMethods: [
"creditCard": [
"splitPayments": [
"maxCards": 2
]
]
]
)
)
)Auto Purchase Configuration for PayPal
The Auto Purchase (automatic purchase) feature for PayPal allows processing payments instantly when:
- The customer has previously linked their PayPal account.
- They have authorized fast payments in their account.
/// MODAL
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
userToken: ..., // optional
styleFile: ..., // optional
callbacks: ...,
paymentMethods: [
[
"paymentMethod": "wallet",
"processors": ["paypal_wallet"],
"configuration": [ "express": true ]
]
]
)Configuration Parameters
| Parameter | Type | Default Value | Description |
|---|---|---|---|
| express | Boolean | true | When true, processes payment automatically if the customer has PayPal linked. When false, allows selecting/confirming the account. |
IMPORTANT: the express configuration will only work if only the PayPal configuration is passed in the paymentMethods parameter.
2. Show or hide payment methods
The Payment Widget can display various payment methods available for an order, without the merchant having to individually add each APM button in their Frontend.
When invoking the initPaymentWidget function, the paymentMethods* parameter defines the payment methods that the widget will show:
-
If only 1 method is passed in
paymentMethods, the widget automatically opens the payment method form without showing buttons for other AMPs.
// MODAL
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
userToken: ..., // optional
styleFile: ..., // optional
callbacks: ...,
paymentMethods: [
[
"paymentMethod": "voucher",
"processors": ["payu_oxxo_cash"]
]
]
)
// EMBEDDED
DeunaWidget(
deunaSDK: deunaSDK,
configuration: PaymentWidgetConfiguration(
orderToken: "YOUR_ORDER_TOKEN",
callbacks: PaymentWidgetCallbacks(
onSuccess: { order in },
onError: { error in },
onEventDispatch: { event, data in }
),
paymentMethods: [
[
"paymentMethod": "voucher",
"processors": ["payu_oxxo_cash"]
]
]
)
)
// MODAL
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
userToken: ..., // optional
styleFile: ..., // optional
callbacks: ...,
paymentMethods: [
[
"paymentMethod": "voucher",
"processors": ["daviplata"]
]
]
)
// EMBEDDED
DeunaWidget(
deunaSDK: deunaSDK,
configuration: PaymentWidgetConfiguration(
orderToken: "YOUR_ORDER_TOKEN",
callbacks: PaymentWidgetCallbacks(
onSuccess: { order in },
onError: { error in },
onEventDispatch: { event, data in }
),
paymentMethods: [
[
"paymentMethod": "voucher",
"processors": ["daviplata"]
]
]
)
)
// MODAL
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
userToken: ..., // optional
styleFile: ..., // optional
callbacks: ...,
paymentMethods: [
[
"paymentMethod": "voucher",
"processors": ["nequi_push_voucher"]
]
]
)
// EMBEDDED
DeunaWidget(
deunaSDK: deunaSDK,
configuration: PaymentWidgetConfiguration(
orderToken: "YOUR_ORDER_TOKEN",
callbacks: PaymentWidgetCallbacks(
onSuccess: { order in },
onError: { error in },
onEventDispatch: { event, data in }
),
paymentMethods: [
[
"paymentMethod": "voucher",
"processors": ["nequi_push_voucher"]
]
]
)
)If more than 1 payment method is specified in the paymentMethodsparameter, then the widget will only show those enabled methods which must be configured at the merchant level.
For credit card processing there is no need to pass the processors's array since the merchant can have multiple configured for the use of routing.
// MODAL
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
userToken: ..., // optional
styleFile: ..., // optional
callbacks: ...,
paymentMethods: [
[
"paymentMethod": "credit_card"
],
[
"paymentMethod": "bnpl",
"processors": ["kueski"]
],
[
"paymentMethod": "voucher",
"processors": ["payu_oxxo_cash"]
]
]
)
// EMBEDDED
DeunaWidget(
deunaSDK: deunaSDK,
configuration: PaymentWidgetConfiguration(
orderToken: "YOUR_ORDER_TOKEN",
callbacks: PaymentWidgetCallbacks(
onSuccess: { order in },
onError: { error in },
onEventDispatch: { event, data in }
),
paymentMethods: [
[
"paymentMethod": "credit_card"
],
[
"paymentMethod": "bnpl",
"processors": ["kueski"]
],
[
"paymentMethod": "voucher",
"processors": ["payu_oxxo_cash"]
]
]
)
)If no method list is specified in paymentMethods and the include_payment_options parameter was not used when creating the order, the widget will show all payment methods configured for the merchant.
// MODAL
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
userToken: ..., // optional
styleFile: ..., // optional
callbacks: ...
)
// EMBEDDED
DeunaWidget(
deunaSDK: deunaSDK,
configuration: PaymentWidgetConfiguration(
orderToken: "YOUR_ORDER_TOKEN",
callbacks: PaymentWidgetCallbacks(
onSuccess: { order in },
onError: { error in },
onEventDispatch: { event, data in }
)
)
)Payment Methods Configuration Priority Table
The following table shows how the payment widget decides which payment forms to show when the paymentMethods parameter is not passed.
Priority | Configuration Source | Description | Behavior when there's only one payment method |
|---|---|---|---|
1 | Payment methods passed when executing the | Payment methods are shown according to those passed when initializing the widget, as long as they are activated and configured at the merchant level. | If only one payment method is passed, the widget automatically opens the payment method form without showing buttons. |
2 | Order and | The order is checked to verify if | If only one payment method is passed, the widget automatically opens the payment method form without showing buttons. |
3 | Methods configured at merchant level | If no payment method is passed either in the | If only one payment method is passed, the widget automatically opens the payment method form without showing buttons. |
3. Listen to widget events
When a transaction is successful or fails, it's important to update your interface to notify users about the transaction result. You can do this by listening to payment widget events through callbacks.
The instance of the PaymentWidgetCallbacks class passed to the initPaymentWidget function allows you to listen to widget events through callbacks. Define the respective callbacks to update your app's interface.
Callbacks
Callback | Modal | Embedded | When is it triggered? |
|---|---|---|---|
| ✅ | ✅ | Executes when payment is completed. This callback contains a parameter of type [String:Any] with the order information. |
| ✅ | ✅ | Executes when an error occurs. This callback contains a parameter of type PaymentsError which identifies the type of error produced. See an example of the callback response here. |
| ✅ | ❌ | Executes when the payment widget modal is closed. This callback contains a parameter of enum type
|
| ✅ | ✅ | Executes when the payment widget detects the BIN of an entered credit or debit card or when the user deletes the entered card number. This callback contains a parameter of type [String:Any] with the BIN information and brand of the entered card. |
| ✅ | ✅ | If the order can be deferred, this callback will execute when the user selects the months to defer. This callback contains a parameter of type [String:Any] with the information about the deferred months selected by the user. |
| ✅ | ✅ | This callback will execute when the user presses the pay button and the payment is being processed. NOTE: If there is any incorrect field in the payment form, this event will not execute. |
| ✅ | ✅ | Executes on all events that the widget may produce. |
NOTE: Use the onError callback to identify if the widget could not be shown or if an error occurred when processing the payment.
onError: { error in // The widget could not be loaded if error.type == .initializationFailed { self.deunaSDK.close() // close the widget return } // The payment was failed if(error.type == .paymentError){ // YOUR CODE HERE } }
Optional features
In addition to the mandatory steps to operate the widget, you have the following customization options:
Close the widget
When the widget is shown in a modal, the payment widget only closes when the user presses the widget's close button or when they press the "back" button on iOS.
To close the modal when a payment is successful or when an error occurs, you must call the close function.
Example
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
userToken: "<DEUNA user token>", // optional
callbacks: PaymentWidgetCallbacks(
onSuccess: { order in
self.deunaSDK.close() // Close the payment widget
// Your additional code
},
onError: nil,
...
)
)Customize widget appearance
Use the setCustomStyle function to customize the Widget's appearance.
await DeunaSDK.setCustomStyle({...});
For more information, go to Style Customization.
Example
// Extension to convert a String to a Dictionary(JSON)
extension String {
func toDictionary() -> [String: Any]? {
guard let data = data(using: .utf8) else {
return nil
}
do {
let dictionary = try JSONSerialization.jsonObject(with: data, options: []) as? [String: Any]
return dictionary
} catch {
print("Error: \(error.localizedDescription)")
return nil
}
}
}
.
.
.
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
userToken: "<DEUNA user token>", // optional
callbacks: PaymentWidgetCallbacks(
onCardBinDetected: { metadata in
self.deunaSDK.setCustomStyle(data: """
{
"theme": {
"colors": {
"primaryTextColor": "#023047",
"backgroundSecondary": "#8ECAE6",
"backgroundPrimary": "#8ECAE6",
"buttonPrimaryFill": "#FFB703",
"buttonPrimaryHover": "#FFB703",
"buttonPrimaryText": "#000000",
"buttonPrimaryActive": "#FFB703"
}
},
"HeaderPattern": {
"overrides": {
"Logo": {
"props": {
"url": "https://images-staging.getduna.com/ema/fc78ef09-ffc7-4d04-aec3-4c2a2023b336/test2.png"
}
}
}
}
}
""".toDictionary() ?? [:]
)
}
...
)
)Refresh the widget
The refetchOrder function updates the payment widget and returns the updated order data.
This function is useful for offering promotions.
A common case is a "20% promotion when paying with Mastercard".
In this scenario, the merchant listens to the onCardBinDetected event to identify the card brand. Then, the merchant updates the order in DEUNA (being responsible for calculating promotions) and, through this function, notifies the widget to update, since the order amount may have changed.
Example of refetchOrder function:
deunaSDK.initPaymentWidget(
orderToken: "<DEUNA order token>",
userToken: "<DEUNA user token>", // optional
callbacks: PaymentWidgetCallbacks(
onCardBinDetected: { metadata in
if let cardBrand = metadata["cardBrand"] as? String, cardBrand == "Mastercard" {
self.deunaSDK.refetchOrder { order in
print("ORDER: \(order)")
}
}
}
...
)
)Demo app
To better understand the Payment Widget integration, check out the example project provided by DEUNA.
This example will help you better understand how to implement the widget in your iOS application.
To access the example project and get more information, refer to the iOS Demo.
Hide the pay button (embedded widget)
When showing the widget embedded with the DeunaWidget view, you can hide the widget's pay button using the hidePayButton: true parameter.
DeunaWidget(
deunaSDK: deunaSDK,
configuration: PaymentWidgetConfiguration(
orderToken: "YOUR_ORDER_TOKEN",
hidePayButton: