Tokenización
Cifra los datos de la tarjeta en el navegador con el Bridge SDK de Tokeflow e intercámbialos por una referencia de token de un solo uso que tu backend puede cobrar.
La tokenización convierte los datos en bruto de la tarjeta en una referencia de token segura de manipular sin que esos datos toquen jamás tus servidores. Con el Bridge SDK, el titular de la tarjeta escribe en los campos seguros de Tokeflow, el SDK cifra los datos en el navegador y tokeflow.cards.tokenize() devuelve un CardToken. Solo envías el tokenId a tu backend, que crea una transacción con él.
Esto mantiene los datos sensibles de la tarjeta fuera del alcance de tu aplicación a la vez que te permite conservar el control total de la interfaz y del flujo de pago.
Los campos seguros de Tokeflow se ejecutan dentro de iframes aislados y de origen cruzado; los datos de la tarjeta se cifran en el navegador y nunca tocan tus servidores. Los scripts de la página no pueden leer el PAN, la fecha de vencimiento ni el CVC en bruto.
Cómo encaja la tokenización
La tokenización es un paso del lado del cliente. El token que produce se intercambia por un cobro en tu servidor, donde reside tu clave secreta.
Nunca envíes datos en bruto de la tarjeta (PAN, CVC, vencimiento) a tu propio backend. Envía solo el tokenId devuelto por tokenize(). El propósito mismo de la tokenización es mantener los datos de la tarjeta fuera del alcance PCI de tus servidores.
tokeflow.cards.tokenize(input, options?)
El método cards.tokenize() cifra los datos recopilados por tus Elements de tarjeta y se resuelve en un CardToken. Acepta dos formas de entrada — combinada o dividida — más un nombre del titular y una dirección de facturación opcionales.
Llama a tokenize() solo después de que el SDK esté inicializado (await tokeflow.init()) y de que tu(s) elemento(s) de tarjeta estén montados. Consulta Quickstart para ver la configuración completa.
Entrada de elemento combinado
Usa el CardElement combinado (número, vencimiento y CVC en un único iframe) y pásalo como card:
const cardElement = tokeflow.createCardElement();
cardElement.mount('#card-element');
const token = await tokeflow.cards.tokenize({ card: cardElement });
console.log(token.tokenId); // tok_...Entrada de campos divididos
Cuando recopilas el número de la tarjeta, el vencimiento y el CVC en iframes separados, pasa cada elemento bajo su propia clave:
const cardNumber = tokeflow.createCardNumberElement();
const cardExpiry = tokeflow.createCardExpirationElement();
const cardCvc = tokeflow.createCardCvcElement();
cardNumber.mount('#card-number');
cardExpiry.mount('#card-expiry');
cardCvc.mount('#card-cvc');
const token = await tokeflow.cards.tokenize({
cardNumber,
expiration: cardExpiry,
cvc: cardCvc,
});La clave del vencimiento es expiration — no expirationDate ni expiry. Usar la clave incorrecta deja el vencimiento sin establecer y la tokenización falla la validación.
Nombre del titular y dirección de facturación opcionales
Ambas entradas aceptan un cardholderName y un billingAddress opcionales. Cada campo puede suministrarse como un elemento montado o como una cadena de texto simple — combínalos según lo requiera tu formulario.
const token = await tokeflow.cards.tokenize({
card: cardElement,
cardholderName: cardholderNameElement, // element or 'Jane Doe'
billingAddress: {
line1: addressLine1Element, // element or string
line2: 'Apt 4B', // string
city: cityElement, // element or string
state: 'CA', // string
postalCode: postalCodeElement, // element or string
country: 'US', // ISO 3166-1 alpha-2
},
});| Field | Type | Required | Description |
|---|---|---|---|
card | CardElement | Condicional | El elemento de tarjeta combinado. Requerido para la entrada combinada. |
cardNumber | CardNumberElement | Condicional | Elemento del número de tarjeta. Requerido para la entrada dividida. |
expiration | CardExpirationElement | Condicional | Elemento del vencimiento. Requerido para la entrada dividida. Ten en cuenta que la clave es expiration. |
cvc | CardCvcElement | Condicional | Elemento del CVC. Requerido para la entrada dividida. |
cardholderName | CardholderNameElement | string | No | Nombre en la tarjeta, como un elemento montado o una cadena de texto. |
billingAddress | BillingAddressInput | No | Dirección de facturación. Cada subcampo es un elemento o una cadena de texto. |
Subcampos de BillingAddressInput: line1, line2, city, state, postalCode, country — cada uno acepta un elemento o una cadena de texto.
Opciones
El segundo argumento opcional transporta metadatos no sensibles para almacenar junto al token y — desde el SDK 2.6.0 — indica si la tarjeta puede guardarse para más adelante.
type TokenPurpose = 'one_time' | 'instrument_enrollment';
interface TokenizeOptions {
metadata?: Record<string, any>; // custom metadata stored with the token
saveCard?: boolean; // inside a checkout session: enroll the card for later use
purpose?: TokenPurpose; // standalone tokenization: which kind of token to mint
}| Opción | Dónde se aplica | Efecto |
|---|---|---|
saveCard | Solo dentro de una sesión de checkout (checkoutSessionId definido). | Para una oferta puntual, true emite un token instrument_enrollment para que la tarjeta pueda guardarse como instrumento de pago. Una oferta recurrente siempre registra, así que ahí la bandera es redundante. Se ignora fuera de una sesión. |
purpose | Solo en la tokenización independiente (sin sesión de checkout). | one_time (predeterminado) emite un token de un solo uso que caduca; instrument_enrollment emite un token sin caducidad que puede guardarse. Dentro de una sesión de checkout el servidor deriva la finalidad de la oferta y de saveCard, e ignora esta opción. |
metadata | En todas partes. | Datos personalizados no sensibles almacenados con el token. |
// Dentro de una sesión de checkout — el cliente marcó "guardar mi tarjeta"
const token = await tokeflow.cards.tokenize(
{ card: cardElement },
{ saveCard: true, metadata: { cartId: 'cart_123' } }
);
// Tokenización independiente — emite un token que pueda guardarse
const token = await tokeflow.cards.tokenize(
{ card: cardElement },
{ purpose: 'instrument_enrollment' }
);Ambas opciones se omiten de la solicitud cuando no se definen, así que dejarlas fuera no es lo mismo que enviar false. Pide el consentimiento del cliente antes de solicitar un token registrable.
Nunca coloques información de identificación personal (PII) del titular ni datos de la tarjeta en metadata. Es únicamente para datos personalizados no sensibles.
tokenize() siempre devuelve un CardToken; nunca guarda la tarjeta por sí mismo. Que la tarjeta se convierta en un instrumento reutilizable se decide en el servidor — mediante la sesión de checkout, mediante save_payment_instrument en el cargo, o mediante una llamada de registro explícita — y cada uno de ellos rechaza un token one_time. Lee el purpose del token devuelto para saber qué obtuviste. Consulta Upsells y downsells en un clic para el flujo completo.
La respuesta CardToken
interface CardToken {
tokenId: string; // your Tokeflow token reference, e.g. 'tok_...'
type: 'card';
brand: string; // 'visa', 'mastercard', etc.
last4: string; // last 4 digits of the card
expiryMonth: string; // e.g. '12'
expiryYear: string; // e.g. '2029'
bin?: string; // bank identification number (optional)
createdAt?: string; // ISO 8601 timestamp (optional)
purpose?: TokenPurpose; // 'one_time' | 'instrument_enrollment' — what the server actually minted
}| Field | Type | Description |
|---|---|---|
tokenId | string | La referencia de token que debes enviar a tu backend. Prefijada con tok_. |
type | 'card' | Siempre card para la tokenización de tarjetas. |
brand | string | Marca de tarjeta detectada (p. ej. visa, mastercard). |
last4 | string | Últimos cuatro dígitos, seguros de mostrar. |
expiryMonth | string | Mes de vencimiento de dos dígitos como cadena de texto. |
expiryYear | string | Año de vencimiento de cuatro dígitos como cadena de texto. |
bin | string? | Número de identificación bancaria, cuando esté disponible. |
createdAt | string? | Marca de tiempo de creación ISO 8601, cuando esté presente. |
purpose | TokenPurpose? | La finalidad con la que el servidor emitió el token — one_time o instrument_enrollment. Compruébala cuando hayas pedido un token registrable: una discrepancia no falla aquí, pero se rechaza después, en el registro o en el cargo. |
Valor de ejemplo:
{
"tokenId": "tok_8f3c2a1b9d4e",
"type": "card",
"brand": "visa",
"last4": "4242",
"expiryMonth": "12",
"expiryYear": "2029",
"bin": "424242",
"createdAt": "2026-01-15T12:30:00.000Z",
"purpose": "one_time"
}brand, last4, bin y el vencimiento son no sensibles y seguros de mostrar en tu interfaz — útiles para una confirmación del tipo "terminada en 4242". El PAN completo y el CVC nunca se devuelven.
Prueba el Bridge SDK sin código
¿Quieres un token para probar la API antes de conectar el SDK? Tokeflow aloja un probador en card.tokeflow.com que ejecuta el Bridge SDK contra tu Merchant y te muestra el token devuelto — la misma referencia tok_… cifrada que recibe tu propia integración. Úsalo para ver exactamente lo que devuelve la tokenización y para alimentar valores de token reales en los endpoints de pago.
- Abre card.tokeflow.com e introduce la clave pública de tu Merchant (
pk_test_…opk_live_…). Las claves secretas nunca se usan en el navegador. - Completa los campos seguros de la tarjeta y envía. La tarjeta se cifra dentro de los iframes aislados y de origen cruzado de Tokeflow — exactamente como en tu propio sitio — de modo que el PAN en bruto nunca sale del navegador.
- Inspecciona la referencia de token devuelta (
tok_…) junto con sus detalles no sensibles (brand,last4, vencimiento). - Pasa ese valor como
card_ciphertext_idpara probar tus endpoints de método de pago — por ejemploPOST /api/v1/transactions.
Cada token es de un solo uso y de corta duración — genera uno nuevo para cada cobro de prueba. Usa una clave pública de prueba (pk_test_…) mientras integras, para que no haya fondos reales involucrados. Consulta Environments and keys.
Intercambiar el token por un cobro
El token es una referencia, no un cobro. Después de que tokenize() se resuelva, envía el tokenId a tu propio backend y deja que tu servidor cree la transacción con su clave secreta.
1. Tokeniza en el navegador
const token = await tokeflow.cards.tokenize({ card: cardElement });
await fetch('/api/payments', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ tokenId: token.tokenId }),
});2. Crea la transacción desde tu servidor
Tu backend intercambia el tokenId por una transacción. Usa una clave secreta — nunca la expongas en el navegador — y envía una Idempotency-Key para que los reintentos no dupliquen el cobro.
curl -X POST https://api.tokeflow.com/api/v1/transactions \
-H "Authorization: Bearer sk_live_mer_xxx" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6b1f7e2c-9a44-4f1e-8c3d-1a2b3c4d5e6f" \
-d '{
"amount": 9900,
"currency": "BRL",
"payment_method": "credit_card",
"card_ciphertext_id": "tok_8f3c2a1b9d4e",
"customer_id": "cust_9f2a1c"
}'Ejemplo de respuesta exitosa:
{
"success": true,
"data": {
"id": "tx_4d2e1a9c7b",
"status": "authorized",
"amount": 9900,
"currency": "BRL",
"payment_method": "credit_card",
"charge_type": "payment",
"customer_id": "cust_9f2a1c",
"created_at": "2026-01-15T12:30:01.000Z"
},
"request_id": "req_8f3c2a1b",
"timestamp": "2026-01-15T12:30:01.000Z"
}El importe está en unidades menores enteras (centavos). 9900 con "currency": "BRL" es R$99.00. Envía siempre la currency ISO 4217.
Los importes de dinero y las decisiones de enrutamiento se toman en tu servidor con tu clave secreta. El navegador nunca ve la clave secreta, ni el importe que no puede manipular, ni el conector que gestiona el cobro. Consulta Authentication para el ámbito de las claves.
Manejo de errores
tokenize() rechaza con un TokeflowError que lleva un code legible por máquina. Maneja los casos comunes para darle al titular de la tarjeta retroalimentación accionable. Consulta la lista completa en Error Handling.
import { TokeflowError, TokeflowErrorCode } from '@tokeflow_com/bridge-js';
try {
const token = await tokeflow.cards.tokenize({ card: cardElement });
// ... send token.tokenId to your backend
} catch (error) {
if (error instanceof TokeflowError) {
switch (error.code) {
case TokeflowErrorCode.ELEMENT_INCOMPLETE:
showError('Please complete all card fields');
break;
case TokeflowErrorCode.INVALID_CARD:
showError('Please check your card number');
break;
case TokeflowErrorCode.EXPIRED_CARD:
showError('This card has expired');
break;
case TokeflowErrorCode.UNSUPPORTED_CARD_BRAND:
showError('This card brand is not supported');
break;
case TokeflowErrorCode.NETWORK_ERROR:
showError('Network error. Please try again.');
break;
default:
showError(error.message);
}
}
}| Code | When it happens |
|---|---|
ELEMENT_INCOMPLETE | Un campo de tarjeta requerido no está completamente ingresado. |
ELEMENT_INVALID | El valor de un elemento no es válido. |
INVALID_CARD | El número de tarjeta falló la validación. |
EXPIRED_CARD | La fecha de vencimiento de la tarjeta está en el pasado. |
UNSUPPORTED_CARD_BRAND | La marca de tarjeta no está habilitada para este Merchant. |
TOKENIZATION_FAILED | No se pudo completar la tokenización. |
NOT_INITIALIZED | Se llamó a tokenize() antes de que init() se resolviera. |
ELEMENT_NOT_MOUNTED | Un elemento pasado no estaba montado en el DOM. |
NETWORK_ERROR | La solicitud a Tokeflow falló en la capa de red. |
Lee el getState() del elemento ({ empty, valid, invalid, complete }) antes de llamar a tokenize(), y deshabilita tu botón de pago hasta que state.complete && state.valid. Esto detecta la entrada incompleta antes de un viaje de ida y vuelta. Consulta Elements.
Próximos pasos
- Elements — crea y aplica estilos a los campos seguros que pasas a
tokenize(). - Upsells y downsells en un clic — guarda la tarjeta durante la compra y vuelve a cobrarla con un clic.
- Checkout — vincula una sesión creada en el backend para impulsar un flujo de checkout completo.
- Error Handling — la referencia completa de
TokeflowErrorCode. - Authentication — claves públicas vs. secretas y el ámbito de las claves.