Personalización de estilos mediante CustomStyle

Introducción

Esta documentación te proporcionará información detallada sobre cómo poder editar la apariencia de tu Payment Widget , Payment Vault o Payment Link. Está dirigida a desarrolladores y comercios interesados en adaptar la apariencia del widget de pagos de acuerdo a sus necesidades específicas.

Requisitos Previos

Antes de comenzar, asegúrese de contar con las siguientes informaciones:

  • API keys 🔑
  • Merchant ID 🪪
  • Identifica las vistas o estilos que desees personalizar y ajusta el archivo JSON incluyendo todos tus requerimientos 💅

📘

Para mayor claridad, a continuación encontrarás el JSON por secciones, debes combinarlos en un solo JSON para enviar todas las configuraciones deseadas.

Configuración de Estilos Básicos

Puedes cambiar colores de fondo, textos y botones. Todo esto incluyendo los siguientes campos en el JSON. Los colores los manejamos en HEX.

{
  "theme": {
    "colors": {
      "primaryTextColor": "#323237",
      "backgroundSecondary": "#FFFFFF",
      "backgroundPrimary": "#FFFFFF",
      "buttonPrimaryFill": "#17171A",
      "buttonPrimaryHover": "#69696E",
      "buttonPrimaryText": "#FFFFFF",
      "buttonPrimaryActive": "#5F529E"
      }
    }
  }

Ejemplo

Vista One Time Password (OTP)

La vista OTP solicita al usuario ingresar un código de un solo uso enviado a su correo electrónico o teléfono (recordar que esta funcionalidad es opcional). Esta sección detalla cómo personalizar elementos clave, como el encabezado, los botones de cambio de canal y la opción de continuar como invitado.

{
  "OtpPage": {
    "overrides": {
      "Header": {
        "props": {
          "overrides": {
            "Logo": {
              "props": {
                "url": "https://live.staticflickr.com/6164/6144091654_cbc351c8e2_b.jpg"
              }
            }
          }
        }
      },
      "Headings": {
        "props": {
          "title": "Ingresa el código de verificación",
          "description": "Para ver tus tarjetas guardadas ingresa el código enviado a"
        }
      },
      "OtpChangeChannelButton": {
        "props": {
          "description": {
            "sms": "Enviar código por correo",
            "email": "Enviar código por SMS"
          }
        }
      },
      "ContinueAsGuestButton": {
        "props": {
          "description": "Continuar sin ingresar el código"
        }
      }
    }
  }
}

Ejemplo

Vista Principal

La vista principal es donde los usuarios interactúan con los elementos principales. Esta sección proporciona una guía sobre cómo configurar y personalizar los patrones de información de la tarjeta, los términos y condiciones, y los botones de pago.

{
  "CardInfoPattern": {
    "title": "Pago con tarjeta de crédito o débit",
    "subtitle": {
      "content": "Ingresa los datos de tu tarjeta"
    }
  },
  "CardPattern": {
    "translations": {
      "es": {
        "inputs": {
          "identityNumber": {
            "label": "Número de documento"
          },
          "identityDocument": {
            "label": {
              "CO": "CO: Cédula / Doc de identidad",
              "CL": "CL: RUT/DNI",
              "EC": "EC: Cédula / Doc de identidad",
              "MX": "MX: Otro documetnto",
              "BR": "BR: CPF/ CNPJ del titular",
              "AR": "AR: DNI / Doc de identidad",
              "UY": "UY: Cédula / Doc de identidad"
            }
          },
          "cardNumber": {
            "label": "Número de tarjeta"
          },
          "cardHolder": {
            "label": "Nombre en la tarjeta"
          },
          "installment": {
            "label": "Selecciona las cuotas",
            "withoutInstallments": "Sin cuotas"
          }
        }
      }
    }
  },
  "TermsConditionsPattern": {
    "showForGuest": true,
    "showForAuth": false,
    "legalMessage": "Al continuar aceptas las",
    "connectorText": "y",
    "hideCompanyDisclaimer": false
  },
  "PaymentButtonPattern": {
    "label": "Pagar",
    "showOrderTotal": true,
    "styles": {
      "padding": "10px 20px",
      "borderRadius": "25px"
    }
  },
 "PoweredByPattern": {
    "url": "https://images-staging.getduna.com/checkout_modular/deuna-logo-sm.svg",
    "imageStyle": { "width": "50px", "height": "200px" },
    "hide": true
  }
  
    }
}

Ejemplo

Vista Usuarios Autenticado

Esta vista se muestra una vez el usuario se ha autenticado a través de OTP o fue autenticado de manera "frictionless" con nuestra tecnología de device fingerprint. Es en esta vista donde los usuarios interactúan con sus tarjetas previamente guardadas. Esta sección proporciona una guía sobre cómo configurar y personalizar los patrones de información de la tarjeta y gestión de la misma.

{
  "UserCardPattern": {
    "translations": {
      "es": {
        "addNewCard": {
          "info": "Agregar una tarjeta"
        },
        "moreOptions": {
          "payWith": "Tarjeta seleccionada"
        },
        "paymentMethods": {
          "seeAllMyCards": "Ver tarjetas guardadas",
          "expiredCard": "Tarjeta expirada",
          "warningExpiredCard": "Selecciona un método de pago disponible",
          "confirmDeleteMethodTitle": "Eliminar esta tarjeta",
          "deleteMainText": "Eliminar",
          "confirmDeleteMethodAccept": "Confirmar",
          "confirmDeleteMethodCancel": "Cancelar",
          "confirmDeleteMethod": "Ten en cuenta que al eliminarla no podrás restaurarla."
        }
      }
    }
  }
}

Ejemplo

Estructura completa CustomStyle

El archivo CSSStyleFile contiene la configuración de estilos para Payment Widget o Payment Vault. A continuación, se presenta una descripción detallada de los componentes editables y personalizables.

Ejemplo de una estructura JSON válida para la configuración de estilos:

{
  "theme": {
    "colors": {
      "primaryTextColor": "#323237",
      "backgroundSecondary": "#FFFFFF",
      "backgroundPrimary": "#FFFFFF",
      "buttonPrimaryFill": "#17171A",
      "buttonPrimaryHover": "#69696E",
      "buttonPrimaryText": "#FFFFFF",
      "buttonPrimaryActive": "#5F529E"
    }
  },
  "OtpPage": {
    "overrides": {
      "Header": {
        "props": {
          "overrides": {
            "Logo": {
              "props": {
                "url": "https://live.staticflickr.com/6164/6144091654_cbc351c8e2_b.jpg"
              }
            }
          }
        }
      },
      "Headings": {
        "props": {
          "title": "Ingresa el código de verificación",
          "description": "Para ver tus tarjetas guardadas ingresa el código enviado a"
        }
      },
      "OtpChangeChannelButton": {
        "props": {
          "description": {
            "sms": "Enviar código por correo",
            "email": "Enviar código por SMS"
          }
        }
      },
      "ContinueAsGuestButton": {
        "props": {
          "description": "Continuar sin ingresar el código"
        }
      }
    }
  },
  "CardInfoPattern": {
    "title": "Pago con tarjeta de crédito o débito",
    "subtitle": {
      "content": "Ingresa los datos de tu tarjeta"
    }
  },
  "CardPattern": {
    "translations": {
      "es": {
        "inputs": {
          "identityNumber": {
            "label": "Número de documento"
          },
          "identityDocument": {
            "label": {
              "CO": "CO: Cédula / Doc de identidad",
              "CL": "CL: RUT/DNI",
              "EC": "EC: Cédula / Doc de identidad",
              "MX": "MX: Otro documento",
              "BR": "BR: CPF/ CNPJ del titular",
              "AR": "AR: DNI / Doc de identidad",
              "UY": "UY: Cédula / Doc de identidad"
            }
          },
          "cardNumber": {
            "label": "Número de tarjeta"
          },
          "cardHolder": {
            "label": "Nombre en la tarjeta"
          },
          "installment": {
            "label": "Selecciona las cuotas",
            "withoutInstallments": "Sin cuotas"
          }
        }
      }
    }
  },
  "TermsConditionsPattern": {
    "showForGuest": true,
    "showForAuth": false,
    "legalMessage": "Al continuar aceptas las",
    "connectorText": "y",
    "hideCompanyDisclaimer": false
  },
  "PaymentButtonPattern": {
    "label": "Pagar",
    "showOrderTotal": true,
    "styles": {
      "padding": "10px 20px",
      "borderRadius": "25px"
    }
  },
 "PoweredByPattern": {
    "url": "https://images-staging.getduna.com/checkout_modular/deuna-logo-sm.svg",
    "imageStyle": { "width": "50px", "height": "200px" },
    "hide": true
  },
  "UserCardPattern": {
    "translations": {
      "es": {
        "addNewCard": {
          "info": "Agregar una tarjeta"
        },
        "moreOptions": {
          "payWith": "Tarjeta seleccionada"
        },
        "paymentMethods": {
          "seeAllMyCards": "Ver tarjetas guardadas",
          "expiredCard": "Tarjeta expirada",
          "warningExpiredCard": "Selecciona un método de pago disponible",
          "confirmDeleteMethodTitle": "Eliminar esta tarjeta",
          "deleteMainText": "Eliminar",
          "confirmDeleteMethodAccept": "Confirmar",
          "confirmDeleteMethodCancel": "Cancelar",
          "confirmDeleteMethod": "Ten en cuenta que al eliminarla no podrás restaurarla."
        }
      }
    }
  }
}

Definición de cada una de las propiedades

Propiedad Objeto Descripción
theme Objeto Objeto que define la configuración global del tema para colores y estilos.
theme.colors.primaryTextColor String Color primario del texto.
theme.colors.backgroundSecondary String Color de fondo en la vista de OTP.
theme.colors.backgroundPrimary String Color de fondo en la vista principal.
theme.colors.buttonPrimaryFill String Color de relleno del botón principal.
theme.colors.buttonPrimaryHover String Color de relleno del botón principal al pasar el cursor.
theme.colors.buttonPrimaryText String Color del texto del botón principal.
theme.colors.buttonPrimaryActive String Color de relleno del botón principal al hacer clic.
HeaderPattern Objeto Objeto que define sobrescrituras para el encabezado.
HeaderPattern.overrides Objeto Contiene sobrescrituras específicas para componentes del encabezado.
HeaderPattern.overrides.Logo Objeto Objeto que define propiedades para el componente del logo.
HeaderPattern.overrides.Logo.props.url String URL del logo que se mostrará en el encabezado.
CardInfoPattern Objeto Objeto que define la información de la tarjeta.
CardInfoPattern.title String Título de la sección de información de la tarjeta.
CardInfoPattern.subtitle.content String Contenido del subtítulo.
UpperTagPattern Objeto Objeto que define una etiqueta superior personalizada.
UpperTagPattern.title String Título de la etiqueta superior.
UpperTagPattern.description String Descripción de la etiqueta superior.
UpperTagPattern.iconColor String Color del icono de la etiqueta superior.
UpperTagPattern.style Objeto Estilo de la etiqueta superior, como color(color de texto), box-shadow, margin-top y backgroundColor.
UserCardPattern Objeto Objeto que define traducciones y configuraciones para la gestión de tarjetas de usuario.
UserCardPattern.translations.es Objeto Traducciones al español para componentes de gestión de tarjetas de usuario.
UserCardPattern.translations.es.addNewCard.info String Texto para la opción "Agregar nueva tarjeta".
UserCardPattern.translations.es.moreOptions.payWith String Texto para la opción "Pagar con".
UserCardPattern.translations.es.paymentMethods.seeAllMyCards String Texto para ver todas las tarjetas guardadas.
UserCardPattern.translations.es.paymentMethods.expiredCard String Texto que indica una tarjeta expirada.
UserCardPattern.translations.es.paymentMethods.warningExpiredCard String Mensaje de advertencia para seleccionar un método de pago válido.
UserCardPattern.translations.es.paymentMethods.confirmDeleteMethodTitle String Título para el modal de confirmación de eliminación de una tarjeta.
UserCardPattern.translations.es.paymentMethods.deleteMainText String Texto principal para la opción de eliminar.
UserCardPattern.translations.es.paymentMethods.confirmDeleteMethodAccept String Texto para el botón de aceptar en la confirmación de eliminación.
UserCardPattern.translations.es.paymentMethods.confirmDeleteMethodCancel String Texto para el botón de cancelar en la confirmación de eliminación.
UserCardPattern.translations.es.paymentMethods.confirmDeleteMethod String Mensaje indicando que la eliminación es irreversible.
CardPattern Objeto Objeto que define traducciones y configuraciones para campos de entrada de tarjeta.
CardPattern.translations.es.inputs.identityNumber.label String Etiqueta personalizada para el campo del número de identidad.
CardPattern.translations.es.inputs.identityDocument.label Objeto Etiquetas personalizadas para los documentos de identidad en diferentes países.
CardPattern.translations.es.inputs.identityDocument.label.CO String Etiqueta para Colombia: Cédula / Doc de identidad.
CardPattern.translations.es.inputs.identityDocument.label.CL String Etiqueta para Chile: RUT/DNI.
CardPattern.translations.es.inputs.identityDocument.label.EC String Etiqueta para Ecuador: Cédula / Doc de identidad.
CardPattern.translations.es.inputs.identityDocument.label.MX String Etiqueta para México: Número de RFC.
CardPattern.translations.es.inputs.identityDocument.label.BR String Etiqueta para Brasil: CPF/CNPJ del titular.
CardPattern.translations.es.inputs.identityDocument.label.AR String Etiqueta para Argentina: DNI / Doc de identidad.
CardPattern.translations.es.inputs.identityDocument.label.UY String Etiqueta para Uruguay: Cédula / Doc de identidad.
CardPattern.translations.es.inputs.cardNumber.label String Etiqueta personalizada para el campo del número de tarjeta.
cardHolder Objeto Objeto que define la etiqueta para el campo del nombre del titular de la tarjeta.
cardHolder.label String Etiqueta personalizada para el campo del nombre del titular de la tarjeta.
installment Objeto Objeto que define la etiqueta para el campo de cuotas.
installment.label String Etiqueta personalizada para el campo de cuotas.
installment.withoutInstallments String Texto para indicar que no hay cuotas.
LowerTagPattern Objeto Objeto que define una etiqueta inferior personalizada.
LowerTagPattern.title String Título de la etiqueta inferior.
LowerTagPattern.description String Descripción de la etiqueta inferior.
LowerTagPattern.iconColor String Color del icono de la etiqueta inferior.
LowerTagPattern.style Objeto Estilo de la etiqueta superior, como color(color de texto), box-shadow y backgroundColor.
TermsConditionsPattern Objeto Objeto que define la configuración de los términos y condiciones.
TermsConditionsPattern.showForGuest Boolean Indica si se muestran los términos y condiciones para usuarios invitados.
TermsConditionsPattern.showForAuth Boolean Indica si se muestran los términos y condiciones para usuarios autenticados.
TermsConditionsPattern.legalMessage String Mensaje legal personalizado.
TermsConditionsPattern.connectorText String Texto conector en los términos y condiciones.
TermsConditionsPattern.hideCompanyDisclaimer Boolean Indica si se oculta la exención de responsabilidad de la empresa.
PaymentButtonPattern Objeto Objeto que define la etiqueta, estilo y configuración del botón de pago.
PaymentButtonPattern.label String Texto para el botón de pago.
PaymentButtonPattern.showOrderTotal Boolean Indica si se muestra el total del pedido en el formulario.
PaymentButtonPattern.styles Objeto Estilo del botón de pago, como el padding y el radio del borde.
PaymentButtonPattern.styles.padding String Padding del botón de pago.
PaymentButtonPattern.styles.borderRadius String Radio de borde del botón de pago.
PoweredByPattern Objeto Objeto que define estilo y configuración del disclaimer Power by DEUNA.
PoweredByPattern.hide Boolean Indica si se oculta la marca "Powered by".
PoweredByPattern.url String URL del logo que se mostrará en Power By.
PoweredByPattern.imageStyle Objeto Estilo del logo de Power By, width y height.
OtpPage Objeto Objeto que define sobrescrituras para la página de OTP.
OtpPage.overrides Objeto Contiene sobrescrituras específicas para componentes de la página de OTP.
OtpPage.overrides.Header Objeto Objeto que define sobrescrituras relacionadas con el encabezado para la página de OTP.
OtpPage.overrides.Header.props Objeto Propiedades para el encabezado, como la URL del logo.
OtpPage.overrides.Header.props.url String URL del logo que se mostrará en la página de OTP.
OtpPage.overrides.Headings Objeto Objeto que define el título y la descripción para la página de OTP.
OtpPage.overrides.Headings.title String Título personalizado para la página de OTP.
OtpPage.overrides.Headings.description String Texto descriptivo para la página de OTP.
OtpPage.overrides.OtpChangeChannelButton Objeto Objeto que define la descripción para el botón de cambio de canal OTP.
OtpPage.overrides.OtpChangeChannelButton.description Objeto Descripciones para enviar OTP por SMS o correo electrónico.
OtpPage.overrides.OtpChangeChannelButton.description.sms String Descripción personalizada para enviar OTP por SMS.
OtpPage.overrides.OtpChangeChannelButton.description.email String Descripción personalizada para enviar OTP por correo electrónico.
OtpPage.overrides.ContinueAsGuestButton Objeto Objeto que define la descripción para el botón "continuar como invitado".
OtpPage.overrides.ContinueAsGuestButton.description String Texto descriptivo para continuar como invitado.

Implementación

Existen dos maneras de usar el CustomStyle:

  1. Configuración única de uso por defecto: en caso el comercio quiera personalizar su widget de manera default, puede seguir los siguientes pasos:

    1. Crea un theme usando esta API: https://docs.deuna.com/reference/create-theme
  2. Soporte de múltiples configuraciones: en caso el comercio quiera tener múltiples themes, DEUNA lo soporta. Esto usualmente se usa cuando el comercio quiere mostrar nuestros widgets con un look and feel diferente por segmentación. Un ejemplo es: sus usuarios premium/vip que para sus usuarios regulares. Para lograr esto, seguir los siguientes pasos:

    1. Puedes crear múltiples themes usando esta API: https://docs.deuna.com/reference/create-theme
      1. A cada theme le puedes asignar un nombre, por ejemplo:
        1. name: Prime users
        2. name: Regular users
    2. En la respuesta de esa API, vas a obtener un id que va a ser el identificador único de ese theme. Este es un UUID.
    3. Luego, al momento de que el comercio vaya a inicializar nuestros widgets ya sea vía URL o vía nuestros SDKs, puede pasar el id del theme
      1. Ejemplo SDK: https://docs.deuna.com/docs/integracion-payment-widget-ios#par%C3%A1metros
      2. Ejemplo URL: Aquí como luciría tu URL con el customFile añadido en integración via URL:
        https://elements.sandbox.deuna.io/click_to_pay?publicApiKey=${apiKey}&firstName=${encodeURIComponent(firstname)}&lastName=${encodeURIComponent(lastname)}&email=${encodeURIComponent(email)}&cssFile=UUID_FROM_DEUNA
        
        https://elements.sandbox.deuna.io/vault?publicApiKey=${apiKey}&firstName=${encodeURIComponent(firstname)}&lastName=${encodeURIComponent(lastname)}&email=${encodeURIComponent(email)}&cssFile=UUID_FROM_DEUNA
        
        https://pay.sandbox.deuna.io/now/{{order_token}}?cssFile=UUID_FROM_DEUNA
        
  3. Override de los themes usando directamente el CustomStyle JSON al momento de inicializar los widgets: algunos comercios requieren poder cambiar el look-and-feel dependiendo del bin, franquicia, etc. de la tarjeta que ingrese el usuario, por ejemplo. Para esto, nuestros widgets emite un postMessage / callback event con la información de la tarjeta y sobre esto puede el comercio override los CustomStyles.

    1. // Recibir el evento de la información de la tarjeta
      window.addEventListener('message', (event) => {
         let firstParsedData;
         if (typeof event.data === 'string') {
           firstParsedData = JSON.parse(event.data);
          } else {
           firstParsedData = event.data;
          }
      
          // La información de la tarjeta viene en el "parsedData" en el campo "metadata"
          /*
              metadata: {
                 cardBin: number,
                 cardBran: string
              }
          */
          const parsedData = JSON.parse(firstParsedData);
      
          // Este evento se dispara cuando el usuario escribe los primeros 6 dígitos de su tarjeta
          if (
             parsedData &&
             parsedData.type === "onBinDetected"
           ) {
             iframeRef.current?.contentWindow?.postMessage(
               JSON.stringify({
                 type: "setCustomCSS",
                 data: getCustomCSS(parsedData)
               }),
              '*'
              );
           } 
      });
      
      const cardBrands = {
        Mastercard: '#E94F37',
        Visa: '#04264E'
      };
      
      // Ejemplo de función helper de getCustomCSS
      export const getCustomCSS = (parsedData: any) => ({
        theme: {
          colors: {
            primaryTextColor: "#023047",
            backgroundSecondary: "#8ECAE6",
            backgroundPrimary: "#8ECAE6",
            buttonPrimaryFill: "#FFB703",
            buttonPrimaryHover: "#FFB703",
            buttonPrimaryText: "#000000",
            buttonPrimaryActive: "#FFB703"
          }
        },
        CardInfoPattern: {
          title: "Ingresa los datos de tu tarjeta",
          subtitle: {
            content: "Ingresa los datos de tu tarjeta 🔅"
          }
        },
        UpperTagPattern: {
          title: "Tienes 10% de descuento",
          description: `Debido a que tu tarjeta es ${parsedData.data?.metadata?.cardBrand}, tienes descuento`,
          style: {
            color: '#F6F7EB',
            backgroundColor: `${(cardBrands as any)[parsedData.data?.metadata?.cardBrand]}`
          }
        },
        UserCardPattern: {
          translations: {
            es: {
              addNewCard: {
                info: "Agregar nueva tarjeta 🙂"
              },
              moreOptions: {
                payWith: "👀 Pagar con"
              }
            }
          }
        },
        CardPattern: {
          translations: {
            es: {
              inputs: {
                identityNumber: {
                  label: "this is a custom label"
                },
                cardNumber: {
                  label: "This is a number custom"
                },
                cardHolder: {
                  label: "This is a holder custom"
                }
              }
            }
          }
        },
        TermsConditionsPattern: {
          showForGuest: false,
          showForAuth: false,
          legalMessage: "Al continuar, estás aceptando nuestras",
          connectorText: "and",
          hideCompanyDisclaimer: true
        },
        PaymentButtonPattern: {
          label: "Pagar",
          showOrderTotal: true,
          styles: {
            padding: "10px 20px",
            borderRadius: "25px"
          }
        },
       	LegalInfoPattern: {
        	hidePoweredBy: true
          }
      });
      

Ejemplo de una Customización por CustomStyle

Puedes ver en este apartado cómo este CSSCustomFile va a modificar la apariencia de nuestro Vault. Fíjate en las propiedades descritas en este archivo JSON:

{
  "theme": {
    "colors": {
      "buttonPrimaryFill": "#8A2BE2"
    }
  },
  "CardInfoPattern": {
    "title": "¡Dale vida a tu compra!🤩",
    "header": {
      "content": "Introduce los detalles de tu tarjeta aquí."
    }
  },
  "TermsConditionsPattern": {
    "showForGuest": true,
    "showForAuth": false,
    "hideCompanyDisclaimer": true
  },
  "PaymentButtonPattern": {
    "label": "Pagar",
    "showOrderTotal": true,
    "styles": {
      "padding": "10px 20px",
      "borderRadius": "25px"
   },
   "PoweredByPattern": {
    "hide": true
   }
  }
}
Apariencia pre y post aplicación del CSSCustomFile

Apariencia pre y post aplicación del CSSCustomFile