Métodos de pagoApple Pay

Managed Apple Pay

Acepta Apple Pay sobre el Merchant ID de Tonder: la lista de verificación, el registro de dominios, el botón del Web SDK, solución de problemas y pruebas.

Managed Apple Pay (Tonder gestiona la relación con Apple) corre sobre el Merchant ID y el certificado de Tonder: envías tus dominios, alojas un archivo de verificación, y el botón del Web SDK (@tonder.io/web-sdk) hace el resto. El SDK renderiza el botón, presenta la hoja de pago de Apple y procesa el cargo; la transacción cae en /process/ con la misma forma que un pago con tarjeta y dispara los mismos webhooks — tu conciliación no cambia.

Apple Pay tiene dos superficies de integración: el componente de botón del Web SDK, descrito en esta página, y Hosted Checkout 2.0, donde solo agregas apple_pay a payment_method_types al crear la sesión y la página de Tonder muestra el botón. Apple Pay no existe en el SDK legacy. En la API Direct, Apple Pay es Bring Your Own Apple Pay: obtienes el token bajo tu propio Merchant ID y se lo envías a Tonder.

Pruébalo en vivo: el demo de Apple Pay corre el código de esta página — ábrelo en Safari (macOS, iOS o iPadOS) para ver el botón real y el resultado de disponibilidad.

Antes de empezar: lista de verificación

Casi todos los problemas con Apple Pay son de configuración, no de código. Revisa estos puntos en orden; si algo sigue fallando, Solución de problemas por síntoma te dice qué punto es.

En Hosted Checkout 2.0 la página de pago corre en el dominio de Tonder, así que solo aplican Tu cuenta en Tonder y Cómo pruebas. Con el botón del Web SDK en tu propio sitio, aplican todos los puntos.

Tu cuenta en Tonder

  • Apple Pay está habilitado para tu negocio en cada ambiente que uses, sandbox y producción. Pídeselo a tu contacto en Tonder.
  • Nada que configurar con Apple: en este modelo no necesitas cuenta de desarrollador de Apple, y Tonder registra tus dominios. ¿Ya tienes tu propio Merchant ID? Eso es Bring Your Own Apple Pay.

Tus dominios (Web SDK)

  • Tonder tiene todos los dominios que muestran el botón: producción, staging y previews. Cada subdominio es un registro aparte, y el dominio que cuenta es el de la barra de direcciones, no el de un iframe o una CDN.
  • El archivo de verificación que Tonder te envió está publicado en https://<tu-dominio>/.well-known/<nombre del archivo>, servido como lo exige Apple.
  • Si tu sitio filtra tráfico por país, IP o reglas anti-bots, los servidores de Apple aún pueden llegar a /.well-known/ — ver los rangos que debes permitir.
  • Tonder te confirmó las dos condiciones: Apple Pay habilitado y dominio verificado.

Tu código (Web SDK)

  • El checkout es una página HTTPS de nivel superior, no dentro de un iframe.
  • Haces await tonder.init() y renderizas el botón solo cuando tonder.isApplePayAvailable().available es true.
  • <div id="tonder-apple-pay-button"></div> existe y está vacío antes de que corra mount().
  • El callback payment del botón es síncrono: ningún await entre el toque y la hoja.
  • Lees los resultados en events.payment; un rechazo llega en on_completed.
  • Tu opción de tarjeta sigue visible junto al botón.

Cómo pruebas

  • Safari en un iPhone, iPad o Mac reales. El Simulador de iOS muestra el botón y luego cierra la hoja al tocarlo.
  • El dispositivo tiene una tarjeta en Wallet y su región es una donde Apple Pay está disponible (México lo está). Una Mac necesita Touch ID, o un iPhone o Apple Watch cercano con Apple Pay configurado.
  • En sandbox, el dispositivo tiene sesión iniciada con una cuenta de Sandbox Tester de Apple y una de las tarjetas de prueba de Apple. Las tarjetas de prueba de Tonder no se pueden agregar a Wallet.
  • La IP, la ubicación o la VPN del comprador no importan. Solo importa su Wallet.

Paso 1: pide a Tonder habilitarlo y registrar tus dominios

No es un paso de código, y es la razón más común por la que una integración correcta falla en producción.

  • Tonder trata con Apple — en este modelo tú nunca los contactas y no necesitas cuenta de desarrollador de Apple.
  • Tu parte es enviar a Tonder la lista de dominios que mostrarán el botón — los subdominios cuentan por separado — y alojar el archivo de verificación que Tonder te da.

Empieza este paso antes de escribir código: condiciona todo lo demás. Los pasos exactos y los modos de falla están en el README del SDK.

Cómo servir el archivo de verificación

Apple descarga el archivo desde tu servidor y lo compara byte por byte, así que la URL tiene que devolver el archivo mismo:

RequisitoDetalle
Rutahttps://<tu-dominio>/.well-known/<nombre del archivo>, con el nombre exacto que envió Tonder
ContenidoEl archivo tal como lo envió Tonder: sin renombrarlo, editarlo ni volver a guardarlo
ProtocoloHTTPS con un certificado válido, TLS 1.2 o superior
Redirecciones y proxiesNinguno: la URL sirve el archivo directamente
AutenticaciónNinguna: sin login ni token
Content-Typetext/plain, o ninguno

Antes de avisarle a Tonder que el archivo está publicado, abre la URL y revisa el cuerpo de la respuesta, no solo el código de estado. Una app de una sola página con una ruta comodín responde 200 con index.html, así que la URL parece sana mientras sirve otros bytes. Algunos hostings también ocultan los directorios que empiezan con punto: si el tuyo no sirve /.well-known/ por defecto, configúralo.

Si tu sitio restringe el tráfico por país o IP

Apple revisa el archivo desde sus propios servidores, fuera de México. Si tu sitio solo acepta tráfico de México, o un firewall, WAF, CDN o regla anti-bots bloquea clientes desconocidos, el archivo te carga bien a ti y Apple aun así no puede leerlo — y el dominio nunca se verifica. Permite los rangos de verificación de dominios de Apple en /.well-known/:

17.23.4.96/27
17.23.19.0/27
17.23.24.32/27
17.32.139.128/26
17.132.108.64/26
17.140.126.0/26
17.157.32.0/27
17.157.40.128/27
17.157.44.128/27
17.179.144.128/25
17.253.0.0/16

Apple publica esta lista en Setting up your server y la actualiza de vez en cuando; revísala ahí antes de configurar la regla. Solo tu equipo puede cambiar esto — Tonder no está en el camino de esa petición.

Paso 2: renderiza el botón

Apple Pay es el único flujo que no termina en una llamada a pay(). Apple exige que la hoja de pago se abra en el mismo tick que el toque, así que el SDK es dueño del clic, y el resultado llega por los callbacks de events.payment en lugar de una promesa devuelta.

Esos callbacks no son un mecanismo exclusivo de Apple Pay — se disparan para todos los métodos que el SDK cobra, así que un solo conjunto de handlers cubre el checkout completo.

El SDK renderiza el botón dentro de un elemento tuyo. Debe existir antes de mount() y debe quedar vacío — no le pongas un botón, un texto ni un icono dentro:

<div id="tonder-apple-pay-button"></div>
const tonder = createTonder({
  api_key: tonderPublicConfig.api_key,
  environment: 'stage', // cambia a 'production' al salir a producción
  session: { customer: { email: 'ada@example.com' } },
  // Se disparan para TODOS los métodos, no solo Apple Pay. Con pay() corren
  // junto a la promesa que devuelve; Apple Pay no tiene promesa, así que aquí
  // estos callbacks son el único canal.
  events: {
    payment: {
      on_completed: (transaction) => handleResult(transaction),
      on_error: (error) => showError(error.code),
      on_cancel: () => { /* el comprador cerró la hoja — no es un error */ },
    },
  },
});

await tonder.init();

// Pregunta antes de renderizar. La respuesta es un OBJETO, nunca un booleano:
// { available: true }, o { available: false, code, message }. Usar el objeto
// como condición siempre sería verdadero — lee .available.
const availability = tonder.isApplePayAvailable();

if (availability.available) {
  const button = tonder.create('apple_pay_button', {
    // Se llama SÍNCRONAMENTE cuando el comprador toca, así que lee lo que el
    // carrito tenga en ese momento — monto, moneda y referencias pueden
    // cambiar después del mount sin volver a montar el botón. No debe ser
    // async: Apple exige que la hoja abra en el mismo tick que el toque.
    payment: () => ({
      amount: 250,
      currency: 'MXN',
      return_url: 'https://merchant.example.com/return',
      client_reference: 'ORD-001',
    }),
  });
  await button.mount();
} else {
  // No adivines la razón: solo APPLE_PAY_UNSUPPORTED_BROWSER significa
  // "ofrece otro método"; los otros dos códigos son tuyos por arreglar.
  console.info('Apple Pay oculto:', availability.code, availability.message);
}

Cuando la disponibilidad es false

codeSignificaQué hacer
APPLE_PAY_UNSUPPORTED_BROWSEREl navegador no puede correr Apple PayOfrece otro método de pago — es el único código que es problema del comprador
APPLE_PAY_NOT_ENABLEDApple Pay no está habilitado para tu negocioTuyo por arreglar — ver el paso 1
NOT_INITIALIZEDLlamaste antes de que init() terminaraTuyo por arreglar — espera el await tonder.init()

Personaliza el botón

Safari dibuja el control de forma nativa, así que Apple solo permite cambiar estas llaves en customization.apple_pay_button — cualquier otra cosa se ignora:

LlaveEjemplo
type'check-out' (el call to action)
style'black'
locale'es-MX' (el idioma de la etiqueta)
width / height'100%' / '48px'
border_radius'8px'

El SDK lee customization una sola vez en createTonder() — cambiarla implica construir una instancia nueva y volver a montar. Lo mismo aplica a api_key y session.customer.

Un intento liquidado consume sus referencias, sea cual sea el resultado. En on_completed, acuña un client_reference y un idempotency_key nuevos para que el siguiente toque sea una orden nueva con su propio alcance de idempotencia.

Dónde va el botón en tu cajero

Apple Pay gana su lift de conversión dejando que el comprador se salte el formulario de tarjeta por completo — así que el layout que funciona es el exprés: el botón primero, un divisor, y tus demás métodos debajo, intactos.

Checkout
Licencia comercial$250.00 MXN
Tarjeta de crédito o débito

Apple Pay es un método de pago más, no un reemplazo. Mantén visible tu botón de tarjeta de crédito y débito — y todos los demás métodos — junto a él. Un comprador cuyo navegador o wallet no puede usar Apple Pay sigue necesitando una forma de pagar: ese es exactamente el caso de APPLE_PAY_UNSUPPORTED_BROWSER.

Las prácticas siguientes siguen las Human Interface Guidelines de Apple:

PrácticaPor qué
Ofrécelo temprano — posición exprés, arriba del formulario de tarjetaSu valor es saltarse el formulario; esconderlo tras un paso de "elige tu método" lo tira a la basura
Dale al menos la prominencia de tu botón de pago principalEl mismo ancho o mayor, y nunca fuera del viewport cuando el botón de tarjeta no lo está
Ajústalo a los controles de tu cajero con customization.apple_pay_buttonwidth, height y border_radius son la vía sancionada para integrarlo
Renderízalo solo cuando está disponibleNunca muestres un botón de Apple Pay deshabilitado o en gris
Nunca lo reconstruyas ni lo decoresEl contenedor queda vacío y el control nativo de Safari es el único renderizado permitido

El error a evitar es el reemplazo: cambiar el botón de tarjeta por Apple Pay deja varado a todo comprador para quien no está disponible. Los cajeros que convierten conservan ambos.

Lo que queda fuera de esta guía — un id de contenedor personalizado y liberar el botón en un cambio de ruta — está en Apple Pay en el README del SDK.

pay({ payment_method: { type: 'apple_pay' } }) se rechaza a propósito. Apple Pay no puede cobrarse vía pay() — el requisito de gesto de Apple es la razón. Usa el componente de botón.

Paso 3: tu conciliación no cambia

Nada que hacer. El cargo de Apple Pay cae en /api/v1/process/ como tus cargos con tarjeta, produce una transacción con la misma forma y dispara el mismo webhook. Tu handler existente ya lo cubre.

Envía client_reference en el payment del botón exactamente como hoy y tu correlación sigue funcionando. Ver Modelo de webhooks.

Solución de problemas por síntoma

Qué vesPor quéCómo se arregla
No hay botón; la disponibilidad devuelve APPLE_PAY_UNSUPPORTED_BROWSERNo es Safari, no hay tarjeta en Wallet o es el Simulador de iOSPrueba en Safari en un dispositivo real; tus otros métodos cubren al comprador mientras tanto
No hay botón; la disponibilidad devuelve APPLE_PAY_NOT_ENABLEDApple Pay no está habilitado para tu negocioPídeselo a Tonder — ver el paso 1
No hay botón; la disponibilidad devuelve NOT_INITIALIZEDLa revisión corrió antes de que terminara init()Primero await tonder.init()
mount() lanza APPLE_PAY_CONTAINER_NOT_FOUNDEl contenedor no está en la página cuando corre mount()Renderiza el <div> vacío antes de montar
La hoja se abre y se cierra; on_error reporta APPLE_PAY_VALIDATION_ERRORApple no emite sesión para el dominio: archivo ausente o alterado, una redirección o un firewall que bloquea a AppleSirve el archivo, permite los rangos de Apple y pide a Tonder que confirme el dominio
La hoja nunca se abre; on_error reporta APPLE_PAY_SESSION_ERROREl navegador se negó a abrir una hoja de pagoPágina HTTPS de nivel superior, no un iframe, y nada en await antes de la hoja
Funciona en staging, no en producciónEl dominio de producción no está registradoCada dominio es un registro aparte — envíaselo a Tonder

La habilitación y la verificación del dominio son pasos distintos y fallan distinto: sin habilitación nunca aparece el botón (APPLE_PAY_NOT_ENABLED); sin dominio verificado el botón aparece y la hoja se cierra (APPLE_PAY_VALIDATION_ERROR). Pide a Tonder que confirme las dos.

Prueba Apple Pay

PruebaQué demuestra que funcionó
La hoja abre en un dispositivo realEl Simulador de iOS no puede probar Apple Pay web
Un rechazoLlega en on_completed con estado declinado, no en on_error
client_referenceAparece en el webhook y correlaciona tu orden

La fila del rechazo es la que sorprende: on_completed significa que el cargo llegó a una respuesta final, no que la respuesta fue sí.

Las tarjetas de prueba de Apple, la cuenta de Sandbox Tester y la configuración del dispositivo están en la página de Apple Pay. Son las mismas para los dos modelos.

Siguientes pasos

¿Te resultó útil esta página?

En esta página