Create Payment Checkout Form

HTML

Poner a disposición el pago con tarjeta mediante Checkout Form es un proceso sencillo que solo requiere incluir un script en un formulario HTML de estructura básica sin las necesidad de realizar requests directamente a Toku. A continuación, se muestra un ejemplo básico de formulario:

<form id="creditCardForm">
 
  <label for="cardNumber">Card Number:</label>
  <div id="pan" style="width: 17em; height: 3em;"></div>

  <label for="expirationDate">Expiration Date (MM/YY):</label>
  <input type="text" id="expirationDate" name="expirationDate" placeholder="MM/YY" required><br>

  <label for="cvv">CVV:</label>
  <div id="cvv" style="width: 4em; height: 2em;"></div>

  <label for="cardholderName">Cardholder's Name:</label>
  <input type="text" id="cardholderName" name="cardholderName" required><br>

<button id="submitButton" type="button">Submit</button>

</form>

Es importante destacar que los IDs de los elementos <div> asociados al pan y cvv deben coincidir con los inputs del objeto TokuCheckoutForm consumido en el siguiente script para su correcto funcionamiento.

En el caso de un pago usando una tarjeta previamente inscrita, no es necesario el elemento para el pan.

Script

<!-- Import the JavaScript file -->
<script src="https://storage.googleapis.com/toku-embedded-portal/checkout-form.min.js"></script>
<script>
    let tokuCheckoutForm = null;

    document.addEventListener('DOMContentLoaded', function () {
        tokuCheckoutForm = new TokuCheckoutForm({
            panDivId: 'pan',
            cvvDivId: 'cvv',
            environment: params.get('environment') || 'PROD',
            onSuccess: () => {
                console.log('Success');
                hideLoadingIndicator();
            },
            onError: () => {
                console.log('Error');
                hideLoadingIndicator();
            },
            onPanFocus: tokuCheckoutForm => {
                console.log('panFocus');
            },
            onPanBlur: tokuCheckoutForm => {
                console.log('panBlur');
            },
            onCvvFocus: tokuCheckoutForm => {
                console.log('CvvFocus');
              	tokuCheckoutForm.setCvvStylesheet('input { color: green }');
            },
            onCvvBlur: tokuCheckoutForm => {
                console.log('CvvBlur');
              	tokuCheckoutForm.setCvvStylesheet('input { color: red }');
            },
            onPanChange: data => {
                console.log('onPanChange' + JSON.stringify(data));
            },
            onCvvChange: data => {
                console.log('onCvvChange' + JSON.stringify(data));
            },
            onCardValidationLoading: () => {
                console.log('onCardValidationLoading');
            },
            onCardValidationCompleted: data => {
                console.log('onCardValidationCompleted' + JSON.stringify(data));
            },
            panStyle: {
                width: '15em',
                height: '1em',
                'border-radius': '0.5rem',
                border: '2px solid',
                padding: '0.5rem',
                outline: 'none',
            },
            cvvStyle: { width: '3em', height: '1em', 'box-shadow': '0 0 5px rgba(0, 0, 0, 0.2)' },
            options: {
                maskPan: true,
                panPlaceholder: 'Card Number',
                cvvPlaceholder: 'CVV',
            },
            panStylesheet: 'input { color: blue; } input:focus { color: green }',
            cvvStylesheet: '',
            organizationId: <org_id_encrypted>,
            accountId: <acc_id_encrypted>,
            tokuProduct: <toku_product>,
        });
    });

    document.getElementById("submitButton").addEventListener('click', function () {
        const formData = {
            expirationDate: document.getElementById('expirationDate')?.value,
            cardholderName: document.getElementById('cardholderName')?.value,
        };
        tokuCheckoutForm.processOperation("PAYMENT", {
            organizationId: <org_id_encrypted>,
            accountId: <acc_id_encrypted>,
            customerId: <cus_id_encrypted>,
            tokuProducts: [<toku_product>],
            expirationDate: formData.expirationDate,
            customerName: formData.cardholderName,
            invoiceIds: [<in_id1_encrypted>, <in_id2_encrypted>],
            amount: <amount>,
            tokuProductsForInscription: [<toku_product_for_inscription>],
            subscriptionId: <subscription_id_encrypted>,
            paymentMethodId: <payment_method_id_encrypted>,
            installments: <number_of_installments>
        });
    });

    document.getElementById('expirationDate').addEventListener('input', function (e) {
        let input = e.target.value.replace(/\D/g, '').substring(0, 4); // Allow only digits and limit to 4 chars
        if (input.length >= 2) {
            input = input.slice(0, 2) + '/' + input.slice(2); // Add slash after the second digit
        }
        e.target.value = input;
    });
</script>

TokuCheckoutForm

Nombre

Tipo

Descripción

Requerido

panDivId

string

Identificador del div asociado al pan en el form.

No

cvvDivId

string

Identificador del div asociado al cvv en el form.

🔘 Si *

environment

string

Ambiente de trabajo. Debe ser PROD.

🔘 Si *

onSuccess

function

Función gatillada al éxito

🔘 Si *

onError

function

Función gatillada al error

🔘 Si *

onPanFocus

function

Función gatillada al enfocar el input del pan.

No

onPanBlur

function

Función gatillada al desenfocar el input del pan.

No

onCvvFocus

function

Función gatillada al enfocar el input del cvv.

No

onCvvBlur

function

Función gatillada al desenfocar el input del cvv.

No

onPanChange

function

Función gatillada cada vez que el usuario cambia el número de tarjeta. Recibe como primer argumento data un objeto con los siguientes atributos:

  • length: El largo del número de tarjeta ingresado hasta ahora.
  • cardInstitution: visa, mastercard o americanexpress
  • luhnCheck: true si el número ingresado hasta ahora pasa el algoritmo de Luhn.

No

onCvvChange

function

Función gatillada cada vez que el usuario cambia el cvv. Recibe como primer argumento data un objeto con los siguientes atributos:

  • length: El largo del número de tarjeta ingresado hasta ahora.

No

onCardValidationLoading

function

Función gatillada cuando se va a buscar el país y tipo de la tarjeta.

No

onCardValidationCompleted

function

Función gatillada cuando se obtiene el país y tipo de la tarjeta. Recibe como primer argumento data un objeto con los siguientes atributos:

  • success: true si la validación fue exitosa.
  • country: El país de emisión de la tarjeta.
  • type: credit o debit.

No

panStyle

dict

Estilo del input del pan

🔘 Si *

cvvStyle

dict

Estilo del input del cvv

🔘 Si *

panStylesheet

string

Estilos para insertar en un tag <style> en el iframe del pan

No

cvvStylesheet

string

Estilos para insertar en un tag <style> en el iframe del cvv

No

options

dict

maskPan: true para ofuscar el pan cuando se desenfoca el input.

No

organizationId

string

id organization encriptado.

Si

accountId

string

id account encriptado.

Si

tokuProduct

string

Toku product que se usará para procesar el pago. Por ahora, solo soporta payment_orchestration_onetime.

Si

TokuCheckoutForm.processOperation

Nombre

Tipo

Descripción

Requerido

TokuOperationType

string

Tipo de operación a realizar

🔘

Si

*

body

json

Cuerpo para la request

🔘

Si

*

TokuCheckoutForm.processOperation - body

Nombre

Tipo

Descripción

Requerido

organizationId

string

id organization encriptado

🔘

Si

*

accountId

string

id account encriptado

🔘

Si

*

customerId

string

id customer encriptado

🔘

Si

*

tokuProducts

list[string]

Lista de toku products que se usarán para procesar el pago. Por ahora, solo soporta

payment_orchestration_onetime

.

🔘

Si

*

expirationDate

string

Fecha expiración de tarjeta ingresada. Requerido si no se manda

paymentMethodId

.

No

customerName

string

Nombre del portador de tarjeta ingresada. Requerido si no se manda

paymentMethodId

.

No

invoiceIds

list

Lista de id invoices encriptados

🔘

Si

*

amount

float

monto total a pagar

🔘

Si

*

tokuProductsForInscription

list[string]

Lista de toku products que se usarán para inscribir la tarjeta si el pago es exitoso. Por ahora solo soporta

cards_batch_mx_recurring_pst

.

No

subscriptionId

string

Id subscription encriptado. Solo es necesario si se va a inscribir la tarjeta. La tarjeta quedará suscrita para este producto.

No

paymentMethodId

string

Id payment method encriptado. Para pagar con una tarjeta previamente tokenizada.

No

installments

number

Número de Meses sin Intereses, solo es necesario si se desea pagar en Meses sin Intereses.

No

TokuCheckoutForm.setPanStylesheet()

Recibe un string con reglas css y lo inserta dentro de un tag <style> en el iframe del pan.

TokuCheckoutForm.setCvvStylesheet()

Recibe un string con reglas css y lo inserta dentro de un tag <style> en el iframe del cvv.

Ejemplo integrado

El siguiente ejemplo muestra un ejemplo integral para incorporar un formulario de inscripción de tarjetas utilizando Checkout Form, junto con un indicador de carga simple para mejorar la experiencia del usuario.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Checkout Form Example</title>
    <style>
        /* Simple loading spinner styles */
        #loadingIndicator {
            display: none;
            width: 40px;
            height: 40px;
            border: 4px solid rgba(0, 0, 0, 0.1);
            border-radius: 50%;
            border-top-color: #000;
            animation: spin 1s infinite linear;
            margin: 10px auto;
        }

        @keyframes spin {
            to {
                transform: rotate(360deg);
            }
        }
    </style>
</head>

<body>
    <h1>Checkout Form</h1>
    <form id="creditCardForm">
        <div id="cardNumber">
            <label for="cardNumber">Card Number:</label>
            <div id="pan" style="width: 17em; height: 3em;"></div>
        </div>

        <div id="expirationDate">
            <label for="expirationDate">Expiration Date (MM/YY):</label>
            <input type="text" id="expirationDate" name="expirationDate" placeholder="MM/YY" required><br>
        </div>

        <label for="cvv">CVV:</label>
        <div id="cvv" style="width: 4em; height: 2em;"></div>

        <div id="cardholderName">
            <label for="cardholderName">Cardholder's Name:</label>
            <input type="text" id="cardholderName" name="cardholderName" required><br>
        </div>

        <button id="submitButton" type="button">Submit</button>
    </form>
    <div id="loadingIndicator"></div>


    <!-- Import the JavaScript file -->
    <script src="https://storage.googleapis.com/toku-embedded-portal/checkout-form.min.js"></script>
    <script>
        // Get the current URL
        const url = new URL(window.location.href);

        // Get the search parameters
        const params = new URLSearchParams(url.search);

        let tokuCheckoutForm = null;
        document.addEventListener('DOMContentLoaded', function () {
            tokuCheckoutForm = new TokuCheckoutForm({
                panDivId: 'pan',
                cvvDivId: 'cvv',
                environment: params.get('environment') || 'PROD',
                onSuccess: () => {
                    console.log('Success');
                    hideLoadingIndicator();
                },
                onError: () => {
                    console.log('Error');
                    hideLoadingIndicator();
                },
                onPanFocus: tokuCheckoutForm => {
                    console.log('panFocus');
                },
                onPanBlur: tokuCheckoutForm => {
                    console.log('panBlur');
                },
                onCvvFocus: tokuCheckoutForm => {
                    console.log('CvvFocus');
                    tokuCheckoutForm.setCvvStylesheet('input { color: green }');
                },
                onCvvBlur: tokuCheckoutForm => {
                    console.log('CvvBlur');
                    tokuCheckoutForm.setCvvStylesheet('input { color: red }');
                },
                onPanChange: data => {
                    console.log('onPanChange' + JSON.stringify(data));
                },
                onCvvChange: data => {
                    console.log('onCvvChange' + JSON.stringify(data));
                },
                onCardValidationLoading: () => {
                    console.log('onCardValidationLoading');
                },
                onCardValidationCompleted: data => {
                    console.log('onCardValidationCompleted' + JSON.stringify(data));
                },
                panStyle: {
                    width: '15em',
                    height: '1em',
                    'border-radius': '0.5rem',
                    border: '2px solid',
                    padding: '0.5rem',
                    outline: 'none',
                },
                cvvStyle: { width: '3em', height: '1em', 'box-shadow': '0 0 5px rgba(0, 0, 0, 0.2)' },
                options: {
                    maskPan: true,
                    panPlaceholder: 'Card Number',
                    cvvPlaceholder: 'CVV',
                },
                panStylesheet: 'input { color: blue; } input:focus { color: green }',
                cvvStylesheet: '',
                organizationId: params.get('organizationId'),
                accountId: params.get('accountId'),
                tokuProduct: params.get('tokuProduct'),
            });
        });
        document.getElementById("submitButton").addEventListener('click', function (event) {
            showLoadingIndicator();

            const formData = {
                expirationDate: document.getElementById('expirationDate').value,
                cardholderName: document.getElementById('cardholderName').value
            };
            tokuCheckoutForm.processOperation("PAYMENT", {
                organizationId: params.get('organizationId'),
                accountId: params.get('accountId'),
                customerId: params.get('customerId'),
                tokuProducts: [params.get('tokuProduct')],
                expirationDate: params.get('paymentMethodId') && formData.expirationDate,
                customerName: params.get('paymentMethodId') && formData.cardholderName,
                invoiceIds: [params.get('invoiceId')],
                amount: parseFloat(params.get('amount')),
                subscriptionId: params.get('subscriptionId'),
                tokuProductsForInscription: [params.get('tokuProductForInscription')],
                paymentMethodId: params.get('paymentMethodId'),
                installments: Number(params.get('installments'))
            });
        });


        function showLoadingIndicator() {
            document.getElementById('loadingIndicator').style.display = 'block';
            document.getElementById('submitButton').disabled = true;
        }

        function hideLoadingIndicator() {
            document.getElementById('loadingIndicator').style.display = 'none';
            document.getElementById('submitButton').disabled = false;
        }

        document.getElementById('expirationDate').addEventListener('input', function (e) {
            let input = e.target.value.replace(/\D/g, '').substring(0, 4); // Allow only digits and limit to 4 chars
            if (input.length >= 2) {
                input = input.slice(0, 2) + '/' + input.slice(2); // Add slash after the second digit
            }
            e.target.value = input;
        });
    </script>
</body>

</html>