Configure Checkout

This page documents how to set up DEUNA Checkout for your business.

Use address chosen by customer

Include the address within the request in the order tokenization with the following structure:

Schedule deliveries

The Checkout has support for scheduling the delivery of the customer's order.

Allow your customers to schedule the date and time for their order to be delivered.

To configure delivery, include the information within the order payload following the structure below:

{
   "order":{
      "shipping_methods":[
         {
            "code":"delivery",
            "name":"Fast delivery",
            "cost":0,
            "tax_amount":0,
            "min_delivery_date":"",
            "max_delivery_date":""
         },
         {
            "code":"programado",
            "name":"Programmed delivery",
            "cost":0,
            "tax_amount":0,
            "min_delivery_date":"",
            "max_delivery_date":"",
            "scheduler":[
               {
                  "date":"2022-06-21",
                  "start_time":"09:00",
                  "end_time":"22:00",
                  "steps_minutes":15
               },
               {
                  "date":"2022-06-22",
                  "start_time":"09:00",
                  "end_time":"22:00",
                  "steps_minutes":15
               },
               {
                  "date":"2022-06-23",
                  "start_time":"09:00",
                  "end_time":"22:00",
                  "steps_minutes":15
               },
               {
                  "date":"2022-06-24",
                  "start_time":"09:00",
                  "end_time":"22:00",
                  "steps_minutes":15
               },
               {
                  "date":"2022-06-25",
                  "start_time":"09:00",
                  "end_time":"22:00",
                  "steps_minutes":15
               },
               {
                {
                  "date":"2022-06-26",
                  "start_time":"09:00",
                  "end_time":"22:00",
                  "steps_minutes":15
               }
            ]
         }
      ]
   }
}

Additional settings

Set up specific actions for events during the checkout process such as:

  • Changes of address
  • Store changes
  • Coupon changes

Add an checkoutConfig object to the widget configuration object:

const deunaCheckout = window.DunaCheckout();

const config = {
    apiKey: "...",
    env: "staging",
    orderToken: "order token",
    checkoutConfig?: {
  			// Allows that address is editable in the Checkout
        addressReadonly?: boolean,
  			// Removes option to un select the adress tipe and uses "other" as default
        removeAddressTypeSelector?: boolean,
  			// Hides coupon form
        hideCoupons?: boolean,
  			// Hides form to add comments to the order
      	hideAdditionalComments?: boolean,
  			// Select the element where to render the checkout
      	targetSelector?: string,
  			// Hides the form the introduce cash change on order
        disableCashAmount?: boolean,
    }
};

deunaCheckout.configure(config);
deunaCheckout.show();
AttributeDescriptionDefault value
addressReadonlyShow the customer a previously entered address without the possibility of editing.false
removeAddressTypeSelectorHide the address type selector.false
hideCouponsHide form to add and view coupons.false
hideAdditionalCommentsHide form to add additional comments to the order.false
targetSelectorSelect the element to render Checkout.false
disableCashAmountHide the form so that you can enter the requested change for the order.false

Actions

Customize the purchasing process according to your preferences and needs.

To configure actions on checkout events, pass callback functions to the widget's configuration object.

const deunaCheckout = window.DunaCheckout();

const config = {
    apiKey: "...",
    env: "staging",
    orderToken: "Token de la orden",
    actions: {
      // To change commerece granted address
      onAddressEdit: () => {
        window.location.href = "https://somepage.com/address-selector";
      },
      // To change store used by commerce on pickup
      onStoreChange: () => {
        window.location.href = "https://somepage.com/address-selector";
      },
      // To change commerce granted coupons
      onCouponEdit: () => {
        window.location.href = "https://somepage.com/products-selector";
      },
      // Redirect on unknown checkout error
      onAppCrash: () =>{
      	window.location.href = "https://somepage.com";
      }
    }
};

deunaCheckout.configure(config);
deunaCheckout.show();
CallbackDescription
onAddressEditTo change the user's address outside of Checkout, you can implement that callback .
onStoreChangeChange the pickup store.
onCouponEditExchange coupons given by the business.
onAppCrashRedirect to another page if a Checkout error appears.

Callbacks

Configure customizable callbacks in response to certain events.

Add callbacks to the Checkout:

const deunaCheckout = window.DeunaCheckout();

const config = {
    apiKey: "...",
    env: "staging",
    orderToken: "order token",
    // Fix the useful callbacks to trigger a behaviour
    callbacks?:{
  		// Callback is triggered when a successful purchase is done (independent of payment method)
    	onSuccess?: (data) => void;
			// Callback triggered on failed purchase.
      onError?: (data) => void;
			// Callback triggered when the Checkout Widget window is closed
      onSuccess?: (data) => void;
			// Callback to listen to non-main events that are not described previously.
      eventListener?: (eventType, payload)) => void;
     }
};

deunaCheckout.configure(config);
deunaCheckout.show(); 

Priority to display modules

The following table documents the priority for displaying each module:

PrioritySourceDescription
1Modules passed by executing .initPaymentWidgetin checkout_modulesModules are displayed based on what is passed when starting the widget.
2Modules passed through payment link incheckout_modulesThe order is checked to verify if checkout_modules has modules to display.
3Global merchant configurationIf it is not passed in the checkout_modules in the function .initPaymentWidget or in checkout_modules When the order is created, the following are taken: checkout_modules configured at the trade level.

Widget Preloading

Pre-load payment widgets in the background so they appear instantly when your customer is ready to pay.

Why Use It

Without preloading, calling initElements() or initPaymentWidget() loads, configures, and renders the widget all at once — your customer sees a loading state for ~4000-7000ms.

With preloading, the widget loads silently during initialize(). When you later call initElements() or initPaymentWidget(), the widget appears with minimum visible delay for ~2000ms (because of SSR operations).

How It Works

Phase 1: initialize()              Phase 2: initElements()
┌─────────────────────────┐       ┌─────────────────────────┐
│ Widget loads in the     │       │ Widget becomes visible  │
│ background (invisible)  │ ───►  │ instantly.              │
└─────────────────────────┘       └─────────────────────────┘
     On page load                  When user is ready to pay
  • Phase 1 — Call initialize() with preloadWidgets as early as possible (e.g., on page load). The SDK loads the widget in the background. The customer sees nothing.
  • Phase 2 — Call initElements() or initPaymentWidget() when the customer is ready. Pass the orderToken and userToken here. The widget appears instantly.

Quick Start

Elements Widget (Modal)

// Phase 1: On page load
await DeunaSDK.initialize({
  publicApiKey: 'xxxx-xxxx-xxxx',
  env: 'production',
  preloadWidgets: [
    {
      widget: 'elements',
      params: {
        callbacks: {
          onSuccess: (data) => {
            console.log('Payment successful!', data);
            window.location.href = '/thank-you';
          },
          onError: (error) => {
            console.error('Payment error:', error);
          },
          onClosed: (action) => {
            console.log('Widget closed:', action);
          },
        },
      },
    },
  ],
});

// Phase 2: When user clicks "Pay"
await DeunaSDK.initElements({
  orderToken: 'xxxx-xxxx-xxxx',
  userToken: 'xxxx-xxxx-xxxx',
});
// Widget appears instantly

Elements Widget (Embedded)

<div id="payment-container"></div>
// Phase 1
await DeunaSDK.initialize({
  publicApiKey: 'xxxx-xxxx-xxxx',
  env: 'production',
  preloadWidgets: [
    {
      widget: 'elements',
      params: {
        mode: 'target',
        target: '#payment-container',
        callbacks: {
          onSuccess: (data) => console.log('Success!', data),
          onError: (error) => console.error('Error:', error),
        },
      },
    },
  ],
});

// Phase 2
await DeunaSDK.initElements({
  orderToken: 'xxxx-xxxx-xxxx',
  userToken: 'xxxx-xxxx-xxxx',
});

Payment Widget (Modal)

// Phase 1
await DeunaSDK.initialize({
  publicApiKey: 'xxxx-xxxx-xxxx',
  env: 'production',
  preloadWidgets: [
    {
      widget: 'payment',
      params: {
        callbacks: {
          onSuccess: (data) => console.log('Success!', data),
          onError: (error) => console.error('Error:', error),
          onClosed: (action) => console.log('Closed:', action),
        },
      },
    },
  ],
});

// Phase 2
await DeunaSDK.initPaymentWidget({
  orderToken: 'xxxx-xxxx-xxxx',
  userToken: 'xxxx-xxxx-xxxx',
});

API Reference

initialize({ preloadWidgets })

Add the preloadWidgets array to your existing initialize() call.

await DeunaSDK.initialize({
  publicApiKey: string,
  env?: 'production' | 'sandbox' | 'staging' | 'develop',
  preloadWidgets?: PreloadItem[],
});

PreloadItem

// Elements widget
{
  widget: 'elements',
  params: {
    // --- Display ---
    mode?: 'modal' | 'target',           // Default: 'modal'
    target?: string,                      // CSS selector, required when mode is 'target'

    // --- Tokens (can be deferred to Phase 2) ---
    orderToken?: string,
    userToken?: string,

    // --- Localization & Style ---
    language?: 'es' | 'pt' | 'en',
    styleFile?: string,                   // URL to a custom CSS file

    // --- Widget type filter (elements only) ---
    types?: Array<{ name: 'vault' | 'click_to_pay' }>,

    // --- User info ---
    userInfo?: {
      firstName?: string,
      lastName?: string,
      email?: string,
    },

    // --- Appearance ---
    widgetExperience?: {
      theme?: {
        mainColor?: string,
        secondaryColor?: string,
        backgroundColor?: string,
        font?: string,
        imageUrl?: string,
        banner?: string,
        mainActionButtonText?: string,
      },
      userExperience?: {
        showSavedCardsFlow?: boolean,
        defaultCardFlow?: boolean,
        disableInstallments?: boolean,
      },
      flags?: {
        allowSaveUserInfo?: boolean,
      },
      checkoutModules?: Array<{
        name: string,
        props: { hideProductImage: boolean, showInMainView: boolean, fields: any[] },
      }>,
    },

    // --- Behavior ---
    behavior?: {
      hidePayButton?: boolean,
      paymentMethods?: {
        creditCard?: {
          splitPayments?: { maxCards: number },
          flow?: 'tokenize' | 'purchase',
        },
        paypal?: {
          flow?: 'tokenize' | 'purchase',
        },
        bankTransfer?: {
          splitPayments?: boolean,
        },
        flowType?: { type: 'twoStep' | 'singleStep' },
      },
    },

    // --- Callbacks ---
    callbacks?: {
      onSuccess?: (data: object) => void,
      onError?: (error: { type: string, metadata: { code: string, message: string } }) => void,
      onClosed?: (action: 'userAction' | 'systemAction') => void,
      onEventDispatch?: (event: string, payload: object) => void,
      onResize?: (dimensions: { height: number, width: number }) => void,
      onCardBinDetected?: (data: { cardBin: string, cardBrand: string }) => void,
      onInstallmentSelected?: (data: { cardBin: string, installmentPlanOptionId: string }) => void,
    },
  },
}

// Payment widget — all fields above (except types) plus:
{
  widget: 'payment',
  params: {
    // ... all fields from elements (except types) ...

    // --- Payment methods filter (payment only) ---
    paymentMethods?: Array<{
      paymentMethod: string,
      processors: string[],
      configuration?: {
        express?: boolean,
        flowType?: { type: 'twoStep' | 'singleStep' },
      },
    }>,

    // --- Fraud prevention (payment only) ---
    fraudCredentials?: {
      FRAUD_PROVIDER_A: { propA: 'xxxx-xxxx-xxxx', propB: 'xxxx-xxxx-xxxx' }
    },

    // --- Session (payment only) ---
    sessionId?: string,

    // --- Additional callback (payment only) ---
    callbacks?: {
      // ... same as elements callbacks ...
      onPaymentProcessing?: () => void,
    },
  },
}

Example — Elements Widget

await DeunaSDK.initialize({
  publicApiKey: 'xxxx-xxxx-xxxx',
  env: 'production',
  preloadWidgets: [
    {
      widget: 'elements',
      params: {
        // Display
        mode: 'target',
        target: '#payment-container',

        // Tokens (or defer to Phase 2)
        orderToken: 'xxxx-xxxx-xxxx',
        userToken: 'xxxx-xxxx-xxxx',

        // Localization & Style
        language: 'es',
        styleFile: 'https://cdn.example.com/deuna-custom.css',

        // Widget type filter
        types: [{ name: 'vault' }],

        // User info
        userInfo: {
          firstName: 'Name',
          lastName: 'Lastname',
          email: '[email protected]',
        },

        // Appearance
        widgetExperience: {
          theme: {
            mainColor: '#6200EE',
            secondaryColor: '#03DAC6',
            backgroundColor: '#FFFFFF',
            font: 'Inter',
            mainActionButtonText: 'Pay now',
          },
          userExperience: {
            showSavedCardsFlow: true,
            defaultCardFlow: true,
            disableInstallments: false,
          },
          flags: {
            allowSaveUserInfo: true,
          },
        },

        // Behavior
        behavior: {
          hidePayButton: false,
          paymentMethods: {
            creditCard: {
              splitPayments: { maxCards: 2 },
              flow: 'purchase',
            },
            paypal: { flow: 'purchase' },
            bankTransfer: { splitPayments: false },
            flowType: { type: 'singleStep' },
          },
        },

        // Callbacks
        callbacks: {
          onSuccess: (data) => {
            console.log('Payment successful!', data);
          },
          onError: (error) => {
            console.error('Payment error:', error.metadata.message);
          },
          onClosed: (action) => {
            console.log('Widget closed by:', action); // 'userAction' | 'systemAction'
          },
          onEventDispatch: (event, payload) => {
            console.log('Event:', event, payload);
          },
          onResize: ({ height, width }) => {
            console.log('Widget resized:', height, width);
          },
          onCardBinDetected: ({ cardBin, cardBrand }) => {
            console.log('Card detected:', cardBrand, cardBin);
          },
          onInstallmentSelected: ({ cardBin, installmentPlanOptionId }) => {
            console.log('Installment plan:', installmentPlanOptionId);
          },
        },
      },
    },
  ],
});

Example — Payment Widget

await DeunaSDK.initialize({
  publicApiKey: 'xxxx-xxxx-xxxx',
  env: 'production',
  preloadWidgets: [
    {
      widget: 'payment',
      params: {
        // Display
        mode: 'modal',

        // Tokens (or defer to Phase 2)
        orderToken: 'xxxx-xxxx-xxxx',
        userToken: 'xxxx-xxxx-xxxx',

        // Localization & Style
        language: 'es',
        styleFile: 'https://cdn.example.com/deuna-custom.css',

        // User info
        userInfo: {
          firstName: 'Name',
          lastName: 'Lastname',
          email: '[email protected]',
        },

        // Appearance
        widgetExperience: {
          theme: {
            mainColor: '#6200EE',
            secondaryColor: '#03DAC6',
            backgroundColor: '#FFFFFF',
            font: 'Inter',
            mainActionButtonText: 'Pay now',
          },
          userExperience: {
            showSavedCardsFlow: true,
            defaultCardFlow: true,
            disableInstallments: false,
          },
          flags: {
            allowSaveUserInfo: true,
          },
        },

        // Behavior
        behavior: {
          hidePayButton: false,
          paymentMethods: {
            creditCard: {
              splitPayments: { maxCards: 2 },
              flow: 'purchase',
            },
            paypal: { flow: 'purchase' },
            bankTransfer: { splitPayments: false },
            flowType: { type: 'singleStep' },
          },
        },

        // Payment methods filter (payment only)
        paymentMethods: [
          {
            paymentMethod: 'credit_card',
            processors: ['stripe', 'paymentez'],
            configuration: {
              express: false,
              flowType: { type: 'singleStep' },
            },
          },
        ],

        // Fraud prevention (payment only)
        fraudCredentials: {
          FRAUD_PROVIDER_A: { propA: 'xxxx-xxxx-xxxx', propB: 'xxxx-xxxx-xxxx' },
        },

        // Session ID (payment only)
        sessionId: 'session-abc-123',

        // Callbacks
        callbacks: {
          onSuccess: (data) => {
            console.log('Payment successful!', data);
          },
          onError: (error) => {
            console.error('Payment error:', error.metadata.message);
          },
          onClosed: (action) => {
            console.log('Widget closed by:', action);
          },
          onEventDispatch: (event, payload) => {
            console.log('Event:', event, payload);
          },
          onResize: ({ height, width }) => {
            console.log('Widget resized:', height, width);
          },
          onCardBinDetected: ({ cardBin, cardBrand }) => {
            console.log('Card detected:', cardBrand, cardBin);
          },
          onInstallmentSelected: ({ cardBin, installmentPlanOptionId }) => {
            console.log('Installment plan:', installmentPlanOptionId);
          },
          onPaymentProcessing: () => {
            console.log('Payment is being processed...');
          },
        },
      },
    },
  ],
});

Phase 2 Calls

// For elements widget
await DeunaSDK.initElements({
  orderToken: string,
  userToken?: string,
});

// For payment widget
await DeunaSDK.initPaymentWidget({
  orderToken: string,
  userToken?: string,
});

Important Notes

  • Callbacks go in Phase 1. Define onSuccess, onError, and other callbacks inside preloadWidgets.params. You do not need to repeat them in Phase 2.
  • Tokens can go in either phase. If you have the orderToken at page load, include it in Phase 1. If not, pass it in Phase 2 — the SDK handles the timing automatically.
  • Fully backward compatible. If you don't add preloadWidgets, your existing integration continues to work exactly as before.
  • One widget per type. You can preload one 'elements' widget and one 'payment' widget simultaneously, but not two of the same type.

Migration from Traditional Flow

Before (traditional)

await DeunaSDK.initialize({
  publicApiKey: 'xxxx-xxxx-xxxx',
  env: 'production',
});

// Everything happens here — user waits for loading
await DeunaSDK.initElements({
  orderToken: 'xxxx-xxxx-xxxx',
  userToken: 'xxxx-xxxx-xxxx',
  callbacks: {
    onSuccess: (data) => console.log('Success!', data),
    onError: (error) => console.error('Error:', error),
  },
  target: '#payment-container',
  mode: 'target',
});

After (with preloading)

// Move everything except tokens into initialize()
await DeunaSDK.initialize({
  publicApiKey: 'xxxx-xxxx-xxxx',
  env: 'production',
  preloadWidgets: [                    // <-- add this
    {
      widget: 'elements',
      params: {
        callbacks: {                   // <-- moved from initElements
          onSuccess: (data) => console.log('Success!', data),
          onError: (error) => console.error('Error:', error),
        },
        target: '#payment-container',  // <-- moved from initElements
        mode: 'target',                // <-- moved from initElements
      },
    },
  ],
});

// Only tokens remain here — widget appears instantly
await DeunaSDK.initElements({
  orderToken: 'xxxx-xxxx-xxxx',
  userToken: 'xxxx-xxxx-xxxx',
});
📘

Summary: Move callbacks, mode, target, and other static config into preloadWidgets.params.

Keep only orderToken and userToken in the Phase 2 call.