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.

Las tarjetas guardadas / Card-on-File requieren @tonder.io/web-sdk 0.1.11 o posterior.

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;
}
CampoRequeridoDescripción
api_keySíLlave pública de Tonder para navegador.
environmentSí'sandbox', 'stage' o 'production'.
session.customerPara pay() y tarjetas guardadasIdentidad del cliente.
session.customer.phonePara tarjetas guardadas, en negocios configurados para requerir teléfonoTeléfono del cliente en formato E.164 (+52 + 10 dígitos). No reemplaza al email, que siempre identifica al cliente. Consulta Negocios que requieren teléfono para tarjetas guardadas.
session.secure_tokenPara tarjetas guardadasToken de corta vida generado en tu backend.
presentation_modeNo'redirect' (default) o 'embedded'.
events.presentation.on_openNoSe llama al abrir la vista hosted embebida.
events.presentation.on_closeNoSe llama cuando el comprador cierra la vista embebida.
customization.card_fieldsNoPersonalizació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.

CampoTipoDescripción
labelsCardLabelsTexto sobre cada campo seguro (cardholder_name, card_number, cvv, expiration_month, expiration_year).
placeholdersCardPlaceholdersPlaceholder dentro de cada campo seguro.
stylesCardStylesEstilos globales (card_form) y por campo para inputs, etiquetas, errores e icono de la tarjeta (enable_card_icon).
error_messagesCardFieldErrorMessagesMensajes 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étodoQué haceRequiere 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 sin cobrarla.Sí
tonder.getCustomerCards()Lista las tarjetas guardadas del cliente.Sí
tonder.canSaveCards()true cuando las operaciones con tarjetas guardadas están disponibles para esta sesión. false cuando tu negocio requiere teléfono y session.customer.phone falta o está vacío.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:

CampoContenedor 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;
}
CampoRequeridoDescripción
amountSíMonto del pago (unidades decimales). Debe ser mayor que 0.
currencyNoCódigo de moneda. MXN por defecto.
return_urlSíURL usada tras la autenticación hosted o el redirect.
payment_methodSíTarjeta nueva, tarjeta guardada o un método alternativo habilitado.
billing_addressNoDirección de facturación del comprador. Todos sus campos son opcionales.
client_referenceSíTu referencia de orden — aparece en dashboards, exportes, webhooks y reportes.
idempotency_keyNoLlave estable por intento de pago para que los reintentos no dupliquen cargos.
metadataNoContexto no sensible para conciliación y reportes.

Llaves de metadata con significado en reportes:

LlaveUso en reportes
operation_dateFecha/hora de operación de negocio para reportes y conciliación.
customer_emailEmail mostrado en reportes de transacciones.
customer_idIdentificador de cliente del comercio para filtrado.
business_userUsuario 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.

En un negocio que requiere teléfono para tarjetas guardadas, getCustomerCards() lanza SAVE_CARDS_UNAVAILABLE sin enviar ninguna petición cuando session.customer.phone falta o está vacío — revisa primero tonder.canSaveCards().

tonder.canSaveCards()

Devuelve true cuando las operaciones con tarjetas guardadas están disponibles para esta sesión, y false cuando tu negocio requiere teléfono y session.customer.phone falta o está vacío. Si es false, oculta la UI de tarjetas guardadas y ofrece solo tarjeta nueva: getCustomerCards(), enrollCard() y pay() con saved_card lanzarían SAVE_CARDS_UNAVAILABLE. Consulta Negocios que requieren teléfono para tarjetas guardadas.

tonder.enrollCard()

interface EnrollResult {
  card_id: string;
  subscription_id?: string; // viene cuando Card-on-File está habilitado
}

Guarda la tarjeta nueva montada para session.customer sin cobrarla; requiere session.customer y session.secure_token. Al resolverse, los campos de tarjeta nueva se limpian — actualiza la lista con getCustomerCards(). Cuando Card-on-File está habilitado para tu negocio, un pay({ payment_method: { type: 'card' } }) con tarjeta nueva también guarda la tarjeta, y vuelve de getCustomerCards() con un subscription_id.

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ódigoCuándo ocurreCómo resolverlo
INIT_ERRORFalló la inicialización del SDK.Verifica api_key, environment y el acceso de red.
NOT_INITIALIZEDUn método requiere init() completado.Llama await tonder.init() antes de la operación.
MISSING_CUSTOMERFalta session.customer.Crea el SDK con session.customer.email.
SECURE_TOKEN_REQUIREDLas operaciones de tarjetas guardadas requieren session.secure_token.Genera el token en tu backend y pásalo en createTonder().
SECURE_TOKEN_INVALIDEl secure_token es inválido o expiró (1 hora).Genera un token nuevo y recrea el SDK.
SAVE_CARDS_UNAVAILABLETu negocio requiere teléfono para tarjetas guardadas y session.customer.phone falta o está vacío.Recrea el SDK con session.customer.phone (E.164), u oculta la UI de tarjetas guardadas usando canSaveCards().
CUSTOMER_OPERATION_ERROREl SDK no pudo registrar o consultar session.customer (por ejemplo, falta email).Pasa session.customer.email y reintenta.
CUSTOMER_AUTH_TOKEN_NOT_VALIDLa sesión del cliente con Tonder ya no es válida.Recrea el SDK con un secure_token nuevo.
INVALID_PAYMENT_REQUESTamount, return_url, client_reference o payment_method inválidos.Valida el request antes de llamar pay().
INVALID_APM_CONFIGsafetypayCash/safetypayTransfer sin config.country, config.channel o config.bank_ids.Arma el config con el banco de getPaymentMethodBanks().
MOUNT_COLLECT_ERRORLos campos seguros no pudieron montarse o recolectar datos válidos.Verifica que los contenedores existan y los campos estén completos.
SECURE_FIELDS_LOAD_ERROREl navegador no pudo cargar los campos seguros.Revisa CSP, bloqueadores de anuncios y red.
PAYMENT_PROCESS_ERROREl pago no pudo crearse/procesarse.Inspecciona error.details y reintenta solo si es seguro/idempotente.
FETCH_TRANSACTION_ERRORFalló la consulta de la transacción.Verifica el id y reconcilia desde backend/webhooks.
POLL_TIMEOUT_ERROREl 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.
FETCH_CARDS_ERRORgetCustomerCards() falló.Reintenta; mientras tanto ofrece tarjeta nueva.
SAVE_CARD_ERROR / REMOVE_CARD_ERRORFalló el guardado/eliminación de la tarjeta.Pide otra tarjeta o revisa error.details.
SAVE_CARD_PROCESS_ERRORLos datos de la tarjeta no pudieron procesarse al guardarla.Pide al comprador que revise los datos de la tarjeta.
CARD_ON_FILE_DECLINEDLa tarjeta no pudo enrolarse en Card-on-File.Pide otra tarjeta.
FETCH_PAYMENT_METHODS_ERROR / FETCH_PAYMENT_METHOD_BANKS_ERROREl 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:

EstadoSignificadoQué hacer
SuccessPago completado.Confirma el pedido.
AuthorizedPago autorizado por el procesador.Continúa según tu configuración y reconcilia con webhooks.
PendingAún no es final (3DS por redirect, APM/SPEI asíncrono).Espera el webhook o consulta con getTransaction().
ProcessingEl proveedor sigue procesando.No cumplas todavía.
DeclinedEl emisor/procesador rechazó el pago.Muestra un mensaje recuperable.
FailedEl pago falló.Muestra un mensaje recuperable u ofrece otro método.
CancelledPago cancelado o anulado.No cumplas; permite iniciar un pago nuevo.
ExpiredNo se completó a tiempo.Pide al cliente iniciar un pago nuevo.

Siguientes pasos

¿Te resultó útil esta página?

En esta página