Web
Todos los métodos, opciones y errores del Web SDK.
Referencia del SDK Web de Tonder (@tonder.io/web-sdk,
TypeScript, tipos incluidos). La guía paso a paso está en SDK Web; el código
fuente y README en github.com/tonderio/web-sdk.
import { createTonder, AppError, ErrorKeyEnum } from '@tonder.io/web-sdk';¿Prefieres cargarlo con <script> en vez de npm? Las URLs de CDN aprobadas para stage y producción
están en SDK Web → Instalación.
createTonder(config)
Crea una instancia del SDK para un comprador/sesión.
interface TonderConfig {
api_key: string;
environment: 'sandbox' | 'stage' | 'production';
session?: {
customer?: {
email: string;
first_name?: string;
last_name?: string;
phone?: string;
};
secure_token?: string;
};
presentation_mode?: 'redirect' | 'embedded';
events?: {
presentation?: {
on_open?(): void;
on_close?(): void;
};
};
customization?: TonderCustomization;
}| Campo | Requerido | Descripción |
|---|---|---|
api_key | Sí | Llave pública de Tonder para navegador. |
environment | Sí | 'sandbox', 'stage' o 'production'. |
session.customer | Para pay() y tarjetas guardadas | Identidad del cliente. |
session.secure_token | Para tarjetas guardadas | Token de corta vida generado en tu backend. |
presentation_mode | No | 'redirect' (default) o 'embedded'. |
events.presentation.on_open | No | Se llama al abrir la vista hosted embebida. |
events.presentation.on_close | No | Se llama cuando el comprador cierra la vista embebida. |
customization.card_fields | No | Personalización de los campos seguros (abajo). |
Lanza INIT_ERROR si falta config o api_key, o si environment es inválido.
customization.card_fields
Todos los campos son opcionales; lo omitido usa los defaults del SDK.
| Campo | Tipo | Descripción |
|---|---|---|
labels | CardLabels | Texto sobre cada campo seguro (cardholder_name, card_number, cvv, expiration_month, expiration_year). |
placeholders | CardPlaceholders | Placeholder dentro de cada campo seguro. |
styles | CardStyles | Estilos globales (card_form) y por campo para inputs, etiquetas, errores e icono de la tarjeta (enable_card_icon). |
error_messages | CardFieldErrorMessages | Mensajes de validación (required, invalid y por campo). |
Los valores de estilo usan claves CSS-in-JS del renderizador seguro (p. ej. font_size,
font_family, color, border_color). styles aplica dentro del iframe seguro; el layout
del contenedor (p. ej. .card-field { max-height: 90px; }) se controla con tu propio CSS.
const tonder = createTonder({
api_key: 'pk_test_...',
environment: 'sandbox',
customization: {
card_fields: {
labels: { card_number: 'Número de tarjeta', cvv: 'Código de seguridad' },
placeholders: { card_number: '4111 1111 1111 1111', expiration_month: 'MM' },
styles: {
card_form: {
input_styles: {
base: { color: '#111827', font_family: 'Inter, sans-serif', font_size: '16px' },
focus: { border_color: '#2563eb' },
invalid: { color: '#b91c1c' },
},
label_styles: { base: { color: '#374151', font_weight: '600' } },
error_styles: { base: { color: '#b91c1c' } },
},
enable_card_icon: true,
},
error_messages: { required: 'Completa este campo.', invalid: 'Revisa este campo.' },
},
},
});Métodos
| Método | Qué hace | Requiere init() |
|---|---|---|
tonder.init() | Carga la configuración del comercio y prepara el SDK. Seguro llamarlo más de una vez. | — |
tonder.create('card_fields', options?) | Crea el componente de campos seguros. | No |
card_fields.mount() | Monta los campos seguros en los contenedores. | Sí |
card_fields.unmount() | Desmonta los campos de este componente. | No |
card_fields.reveal(input) | Muestra valores seguros de una tarjeta guardada (nunca el CVV). | Sí |
tonder.pay(input) | Crea un pago. | Sí |
tonder.getTransaction(id) | Lee el estado actual de una transacción. | No |
tonder.enrollCard() | Guarda la tarjeta nueva montada para session.customer. | Sí |
tonder.getCustomerCards() | Lista las tarjetas guardadas del cliente. | Sí |
tonder.removeCustomerCard(card_id) | Elimina una tarjeta guardada. | Sí |
tonder.getPaymentMethods() | Lista los métodos de pago activos del negocio. | No |
tonder.getPaymentMethodBanks() | Lista bancos SafetyPay agrupados por canal. | No |
tonder.create('card_fields', options?)
Sin options, el SDK monta el formulario completo de tarjeta nueva usando los contenedores por
defecto:
| Campo | Contenedor por defecto |
|---|---|
cardholder_name | #collect-cardholder-name |
card_number | #collect-card-number |
expiration_month | #collect-expiration-month |
expiration_year | #collect-expiration-year |
cvv | #collect-cvv (o #collect-cvv-<card_id> para tarjetas guardadas) |
interface CardFieldsOptions {
fields?: (CardField | { field: CardField; container_id?: string })[];
card_id?: string; // para el CVV de una tarjeta guardada
unmount_context?: 'all' | 'none' | 'current' | 'create' | string;
events?: Partial<Record<CardField, {
on_change?(state: CardFieldState): void;
on_blur?(state: CardFieldState): void;
on_focus?(state: CardFieldState): void;
on_ready?(state: CardFieldState): void;
}>>;
}tonder.pay(input)
interface PayInput {
amount: number;
currency?: string;
return_url: string;
payment_method:
| { type: 'card' }
| { type: 'saved_card'; card_id: string }
| { type: string; config?: Record<string, unknown> };
metadata?: Record<string, unknown>;
billing_address?: {
street?: string;
street2?: string;
state?: string;
country?: string;
zip_code?: string;
};
client_reference: string;
idempotency_key?: string;
}| Campo | Requerido | Descripción |
|---|---|---|
amount | Sí | Monto del pago (unidades decimales). Debe ser mayor que 0. |
currency | No | Código de moneda. MXN por defecto. |
return_url | Sí | URL usada tras la autenticación hosted o el redirect. |
payment_method | Sí | Tarjeta nueva, tarjeta guardada o un método alternativo habilitado. |
billing_address | No | Dirección de facturación del comprador. Todos sus campos son opcionales. |
client_reference | Sí | Tu referencia de orden — aparece en dashboards, exportes, webhooks y reportes. |
idempotency_key | No | Llave estable por intento de pago para que los reintentos no dupliquen cargos. |
metadata | No | Contexto no sensible para conciliación y reportes. |
Llaves de metadata con significado en reportes:
| Llave | Uso en reportes |
|---|---|
operation_date | Fecha/hora de operación de negocio para reportes y conciliación. |
customer_email | Email mostrado en reportes de transacciones. |
customer_id | Identificador de cliente del comercio para filtrado. |
business_user | Usuario interno, terminal POS o automatización que originó el pago. |
Devuelve Promise<RawTransaction>. Una transacción que necesita 3DS o instrucciones hosted puede
incluir next_action.redirect_to_url.url; las respuestas de APM/SPEI pueden incluir clabe,
bank_name, payment_instructions y voucher_pdf.
tonder.getCustomerCards()
interface Card {
card_id: string;
card_number: string; // enmascarado
expiration_month: string;
expiration_year: string;
card_scheme: string;
subscription_id: string | null;
}subscription_id solo se devuelve cuando Card-on-File está habilitado para el negocio. Si es
null, monta el campo CVV de la tarjeta guardada antes de llamar pay() con esa tarjeta.
tonder.getPaymentMethods()
interface PaymentMethodInfo {
id: number;
payment_method: string; // el valor que va en payment_method.type de pay()
label: string;
logo: string;
category: string;
}Devuelve Promise<PaymentMethodInfo[]> con los métodos alternativos activos del negocio. Úsalo para
construir la lista de métodos en tu UI en vez de codificarla a mano: payment_method es el valor
que después pasas como payment_method.type en pay().
[
{
"id": 7,
"payment_method": "oxxopay",
"label": "Oxxo Pay",
"logo": "https://...",
"category": "cash"
}
]tonder.getPaymentMethodBanks()
interface PaymentMethodBank {
id: number;
name: string;
code: string;
country: string;
channel: 'WP' | 'OL'; // WP = efectivo, OL = transferencia
logo?: string;
}
interface PaymentMethodBanks {
cash: PaymentMethodBank[];
transfer: PaymentMethodBank[];
}Para safetypayCash / safetypayTransfer, arma payment_method.config con country
(bank.country), channel (bank.channel) y bank_ids: [{ id: bank.code }] — el código de
ruteo bancario, no el bank.id interno.
Tipos
import type {
TonderConfig,
PayInput,
RawTransaction,
Customer,
Card,
EnrollResult,
PaymentMethodInfo,
PaymentMethodBank,
PaymentMethodBanks,
CardFieldsOptions,
CardFieldsComponent,
TonderEvents,
PresentationEvents,
} from '@tonder.io/web-sdk';RawTransaction
pay() y getTransaction() devuelven los campos en snake_case, igual que el API y los
webhooks de Tonder:
interface RawTransaction {
id: string;
operation_type: string;
status: string;
amount: number;
currency: string;
client_reference?: string;
metadata?: Record<string, unknown>;
provider?: string;
created_at?: string;
status_code?: number;
next_action?: {
redirect_to_url?: {
url: string;
verify_transaction_status_url?: string;
};
};
decline_code?: string;
decline_reason?: string;
payment_instructions?: Record<string, unknown>;
voucher_pdf?: string;
clabe?: string;
bank_name?: string;
[key: string]: unknown;
}Errores
Los fallos del SDK se lanzan como AppError. Los rechazos de pago no se lanzan: se devuelven
como transacciones — lee transaction.status. Usa error.code para ramificar; no parsees
error.message.
try {
const transaction = await tonder.pay({ /* ... */ });
} catch (error) {
if (error instanceof AppError) {
console.error(error.code, error.status_code, error.details.system_error);
if (error.code === ErrorKeyEnum.MISSING_CUSTOMER) {
// Recrea el SDK con session.customer.
}
} else {
throw error;
}
}Códigos principales:
| Código | Cuándo ocurre | Cómo resolverlo |
|---|---|---|
INIT_ERROR | Falló la inicialización del SDK. | Verifica api_key, environment y el acceso de red. |
NOT_INITIALIZED | Un método requiere init() completado. | Llama await tonder.init() antes de la operación. |
MISSING_CUSTOMER | Falta session.customer. | Crea el SDK con session.customer.email. |
SECURE_TOKEN_REQUIRED | Las operaciones de tarjetas guardadas requieren session.secure_token. | Genera el token en tu backend y pásalo en createTonder(). |
INVALID_PAYMENT_REQUEST | amount, return_url, client_reference o payment_method inválidos. | Valida el request antes de llamar pay(). |
INVALID_APM_CONFIG | safetypayCash/safetypayTransfer sin config.country, config.channel o config.bank_ids. | Arma el config con el banco de getPaymentMethodBanks(). |
MOUNT_COLLECT_ERROR | Los campos seguros no pudieron montarse o recolectar datos válidos. | Verifica que los contenedores existan y los campos estén completos. |
SECURE_FIELDS_LOAD_ERROR | El navegador no pudo cargar los campos seguros. | Revisa CSP, bloqueadores de anuncios y red. |
PAYMENT_PROCESS_ERROR | El pago no pudo crearse/procesarse. | Inspecciona error.details y reintenta solo si es seguro/idempotente. |
FETCH_TRANSACTION_ERROR | Falló la consulta de la transacción. | Verifica el id y reconcilia desde backend/webhooks. |
POLL_TIMEOUT_ERROR | El 3DS embebido terminó pero la reconciliación no llegó a un estado final a tiempo. | No cumplas desde el cliente; reconcilia con getTransaction() o webhooks. |
SAVE_CARD_ERROR / REMOVE_CARD_ERROR / CARD_ON_FILE_DECLINED | Guardado/eliminación/enrolamiento de tarjeta falló. | Pide otra tarjeta o revisa error.details. |
FETCH_PAYMENT_METHODS_ERROR / FETCH_PAYMENT_METHOD_BANKS_ERROR | El catálogo de métodos/bancos no pudo recuperarse. | Reintenta u ofrece códigos de método conocidos directo en pay(). |
La lista completa (incluidos códigos raros/de compatibilidad) está en el README del SDK.
Estados de pago
Lee el estado en transaction.status:
| Estado | Significado | Qué hacer |
|---|---|---|
Success | Pago completado. | Confirma el pedido. |
Authorized | Pago autorizado por el procesador. | Continúa según tu configuración y reconcilia con webhooks. |
Pending | Aún no es final (3DS por redirect, APM/SPEI asíncrono). | Espera el webhook o consulta con getTransaction(). |
Processing | El proveedor sigue procesando. | No cumplas todavía. |
Declined | El emisor/procesador rechazó el pago. | Muestra un mensaje recuperable. |
Failed | El pago falló. | Muestra un mensaje recuperable u ofrece otro método. |
Cancelled | Pago cancelado o anulado. | No cumplas; permite iniciar un pago nuevo. |
Expired | No se completó a tiempo. | Pide al cliente iniciar un pago nuevo. |
