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 cuandotonder.isApplePayAvailable().availableestrue. <div id="tonder-apple-pay-button"></div>existe y está vacío antes de que corramount().- El callback
paymentdel botón es síncrono: ningúnawaitentre el toque y la hoja. - Lees los resultados en
events.payment; un rechazo llega enon_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:
| Requisito | Detalle |
|---|---|
| Ruta | https://<tu-dominio>/.well-known/<nombre del archivo>, con el nombre exacto que envió Tonder |
| Contenido | El archivo tal como lo envió Tonder: sin renombrarlo, editarlo ni volver a guardarlo |
| Protocolo | HTTPS con un certificado válido, TLS 1.2 o superior |
| Redirecciones y proxies | Ninguno: la URL sirve el archivo directamente |
| Autenticación | Ninguna: sin login ni token |
Content-Type | text/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/16Apple 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
code | Significa | Qué hacer |
|---|---|---|
APPLE_PAY_UNSUPPORTED_BROWSER | El navegador no puede correr Apple Pay | Ofrece otro método de pago — es el único código que es problema del comprador |
APPLE_PAY_NOT_ENABLED | Apple Pay no está habilitado para tu negocio | Tuyo por arreglar — ver el paso 1 |
NOT_INITIALIZED | Llamaste antes de que init() terminara | Tuyo 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:
| Llave | Ejemplo |
|---|---|
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.
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áctica | Por qué |
|---|---|
| Ofrécelo temprano — posición exprés, arriba del formulario de tarjeta | Su 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 principal | El 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_button | width, height y border_radius son la vía sancionada para integrarlo |
| Renderízalo solo cuando está disponible | Nunca muestres un botón de Apple Pay deshabilitado o en gris |
| Nunca lo reconstruyas ni lo decores | El 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é ves | Por qué | Cómo se arregla |
|---|---|---|
No hay botón; la disponibilidad devuelve APPLE_PAY_UNSUPPORTED_BROWSER | No es Safari, no hay tarjeta en Wallet o es el Simulador de iOS | Prueba 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_ENABLED | Apple Pay no está habilitado para tu negocio | Pídeselo a Tonder — ver el paso 1 |
No hay botón; la disponibilidad devuelve NOT_INITIALIZED | La revisión corrió antes de que terminara init() | Primero await tonder.init() |
mount() lanza APPLE_PAY_CONTAINER_NOT_FOUND | El 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_ERROR | Apple no emite sesión para el dominio: archivo ausente o alterado, una redirección o un firewall que bloquea a Apple | Sirve 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_ERROR | El navegador se negó a abrir una hoja de pago | Página HTTPS de nivel superior, no un iframe, y nada en await antes de la hoja |
| Funciona en staging, no en producción | El dominio de producción no está registrado | Cada 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
| Prueba | Qué demuestra que funcionó |
|---|---|
| La hoja abre en un dispositivo real | El Simulador de iOS no puede probar Apple Pay web |
| Un rechazo | Llega en on_completed con estado declinado, no en on_error |
client_reference | Aparece 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
Bring Your Own Apple Pay
Tu propio Merchant ID y certificado, por la API Direct.
Demo de Apple Pay
El botón real, en vivo — ábrelo en Safari.
SDK Web (guía)
Instalación, inicio rápido y métodos alternativos.
Migrar desde API Direct
Apple Pay primero, sin tocar tu checkout actual.
Referencia SDK · Web
Todos los métodos, tipos y errores.
Webhooks
Confirma el pago del lado del servidor.
Apple Pay
Dos formas de aceptar Apple Pay con Tonder: Managed, sobre el registro de Tonder en Apple, o Bring Your Own, con tu propio Merchant ID.
Bring Your Own Apple Pay
Acepta Apple Pay con tu propio Merchant ID de Apple: crea el certificado con el CSR de Tonder y envía el token de pago por la API Direct.
