El contrato webServiceURL: cómo un pase de Apple Wallet se actualiza solo
El pase lleva webServiceURL y un token; el iPhone se registra, recibe un push silencioso y pregunta qué cambió. El contrato de cinco endpoints, explicado.
Un pase de Apple Wallet se actualiza solo porque dentro del archivo viajan dos campos: webServiceURL y authenticationToken. Con ellos, el iPhone se registra contra el servidor del emisor; cuando algo cambia, el servidor envía un push silencioso, el teléfono pregunta qué cambió y descarga la versión nueva — sin app del emisor y sin que el titular toque nada.
Ese es todo el mecanismo. Lo que sigue es el contrato en detalle: los cinco endpoints que tu servidor debe implementar, qué autentica cada uno y los errores que nosotros ya pagamos operándolo en producción para cinco tipos de operación distintos.
Dos campos dentro del pass.json
La respuesta corta: webServiceURL es la URL base de tu web service y authenticationToken es el secreto por pase que el dispositivo presenta al autenticarse. Ambos se hornean dentro del pass.json en el momento de firmar el paquete:
{
"serialNumber": "8a41c9…",
"webServiceURL": "https://tudominio.com/api/apple-passes",
"authenticationToken": "f3c97a…"
}
Tres decisiones de diseño que conviene tomar bien desde el primer día:
- El token es por pase, no por plataforma. En AVEX lo derivamos con HMAC-SHA256 sobre el número de serie, con secreto rotable por institución emisora. Un secreto plano compartido por toda la flota convierte cualquier filtración en un incidente de toda la flota.
- La URL compromete el dominio a largo plazo. El pase re-descargado trae la URL que tu servidor emita en ese momento, así que puedes migrarla mientras el dominio viejo siga respondiendo. Si el dominio muere primero, los pases instalados quedan huérfanos: nunca van a preguntar a la dirección nueva.
- HTTPS en producción. La documentación de Apple permite HTTP solo durante desarrollo; en producción el web service responde por HTTPS.
El registro: qué pasa cuando el titular instala el pase
Directo: al instalar el pase, el iPhone llama a tu servidor —
POST {webServiceURL}/v1/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}/{serialNumber}
Authorization: ApplePass {authenticationToken}
— con el pushToken del dispositivo en el body. Tu servidor guarda la tupla (dispositivo, pase, pushToken) y responde 201 si el registro es nuevo o 200 si ya existía.
Dos piezas de esa URL merecen atención. El deviceLibraryIdentifier es un identificador opaco que genera iOS: funciona como secreto efectivo del dispositivo y va a reaparecer en el endpoint más traicionero del contrato. Y el pushToken es la dirección a la que enviarás el push silencioso cuando algo cambie — sin registro guardado no hay actualización posible.
Los cinco endpoints del contrato
El web service completo son cinco rutas. Tres exigen el header Authorization: ApplePass; dos no lo llevan:
- Registrar dispositivo —
POST /v1/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}/{serialNumber}. ConApplePass. Crea la tupla dispositivo-pase. - Listar pases actualizados —
GET /v1/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}?passesUpdatedSince={tag}. Sin Authorization (ver la sección siguiente). Devuelve los números de serie con cambios y unlastUpdatednuevo, o 204 si no hay nada. - Descargar el pase —
GET /v1/passes/{passTypeIdentifier}/{serialNumber}. ConApplePass. Responde el.pkpassfirmado completo. - Anular el registro —
DELETE /v1/devices/{deviceLibraryIdentifier}/registrations/{passTypeIdentifier}/{serialNumber}. ConApplePass. El titular eliminó el pase del wallet. - Log —
POST /v1/log. Sin auth. iOS envía ahí mensajes de error legibles cuando algo del contrato le molesta: es tu mejor herramienta de depuración el primer día.
La trampa que mata la cadena completa: el listado va sin Authorization
Por especificación de Apple, el endpoint que lista pases actualizados no lleva header Authorization — el iPhone simplemente no lo envía en esa llamada. Si tu servidor exige el token ahí, respondes 401 a todos los dispositivos reales y la cadena de actualización muere completa: el push llega, el dispositivo pregunta qué cambió, recibe 401 y nunca descarga nada. Sin error visible para nadie: el pase solo se queda viejo.
Lo sabemos porque lo vivimos: en julio de 2026 un endurecimiento de seguridad bien intencionado agregó ese gate y el síntoma fue exactamente ese silencio. La evidencia que lo delató en producción: el mismo dispositivo recibía 401 en el listado y 200 en el DELETE autenticado un segundo después. El modelo de seguridad no pierde nada al quitarlo: el deviceLibraryIdentifier es un identificador opaco que solo iOS conoce, y cada pareja dispositivo-pase ya fue autenticada con su token en el registro — el listado solo devuelve serials cuya posesión ese dispositivo ya probó. El contenido sigue protegido: la descarga del pase sí exige y verifica el token.
El flujo completo de una actualización
Cuando cambia un dato del pase, la secuencia es:
- Tu servidor marca el pase como actualizado (avanza su
lastUpdated) y envía el push silencioso alpushTokende cada dispositivo registrado. El push no lleva contenido: es un timbre. - El dispositivo llama al listado con su cursor
passesUpdatedSincey recibe los serials que cambiaron desde entonces, más el tag nuevo. - Por cada serial, el dispositivo hace GET del pase y tu servidor responde el
.pkpasscompleto, regenerado y firmado con el contenido vigente — y con el certificado vigente, que es lo que hace invisible una rotación del certificado. - Wallet re-renderiza el pase. Si el campo que cambió declara un
changeMessage, el titular ve el aviso en pantalla; si no, el pase simplemente amanece al día.
El detalle que más confusión evita: Apple no «parchea» campos individuales. Cada descarga regenera el archivo completo, así que la estructura del pase no queda congelada en el teléfono — campos, textos, colores e imágenes se re-componen en cada GET con lo que tu servidor emita en ese momento.
Detalles de producción que la documentación no subraya
- Los 4xx van con cuerpo vacío. Un 401 con body JSON explicativo le regala a un atacante una forma de distinguir serials válidos de inválidos por la forma de la respuesta. Respuesta vacía, siempre.
If-Modified-Sincefunciona con precisión de segundos. Las fechas HTTP no llevan milisegundos: trunca ambos lados al segundo antes de comparar, o vas a responder 304 y 200 de forma errática. Y a un pase anulado nunca le respondas 304 — el dispositivo debe re-descargar la versión sin validez aunque el timestamp coincida (qué viaja en esa versión y cómo se entrega el void).lastUpdatedes un cursor, no cosmética. El dispositivo te lo devuelve tal cual enpassesUpdatedSince; si no avanza cuando el contenido cambia, el listado responde vacío y la actualización nunca ocurre.- El 204 también comunica. Nada que actualizar es una respuesta correcta y frecuente; devolverla bien evita descargas de más.
Preguntas frecuentes
¿El titular necesita una app del emisor para que el pase se actualice?
No. El contrato de actualización es entre iOS y el servidor del emisor: el iPhone se registra solo, recibe el push silencioso y descarga la versión nueva. Apple Wallet ya está instalado — esa es la gracia del canal.
¿Qué contiene el push que dispara la actualización?
Nada visible. Es un push silencioso de contenido mínimo cuyo único trabajo es que el dispositivo pregunte qué cambió. El texto que el titular ve en pantalla sale del changeMessage del campo que cambió, no del push. La anatomía exacta de ese push — y sus tres errores clásicos — está en APNs para pases digitales.
¿Qué pasa si el teléfono está sin conexión cuando cambia el pase?
El estado converge al reconectar: el dispositivo recibe el aviso pendiente o consulta con su cursor passesUpdatedSince y descarga la versión vigente. El pase instalado sigue funcionando offline con su último contenido mientras tanto — la verdad del offline, en detalle.
¿Puedo cambiar el diseño de un pase ya instalado?
Sí: campos, colores, textos e imágenes viajan en la siguiente descarga, porque el archivo se regenera completo en cada GET. Lo que en la práctica no se cambia post-instalación es el estilo del pase (generic, storeCard, eventTicket): fijarlo bien desde la primera emisión evita re-emitir después. El detalle de esa decisión está en pase genérico vs tipos nativos.
Sigue leyendo
Todas las guíasEl certificado WWDR de Apple: el intermedio que viaja dentro de cada .pkpass
El WWDR es el intermedio público de Apple que va dentro de la firma de cada .pkpass. Qué generación usar (G4), cuándo vence y cómo falla cuando falta.
Expirar un pase: voided, expirationDate, validTimeInterval — y qué ve el titular sin conexión
Apple evalúa voided y expirationDate dentro del pase; Google expira por validTimeInterval o state vía PATCH. Sin red, el titular ve lo último descargado.