
En resumen
Un .pkpass es un ZIP con pass.json, un manifest con hashes SHA-1, una firma PKCS#7 y tus imágenes. Si un solo byte no coincide, Wallet rechaza el pase sin dar un error útil.
Un pase de Apple Wallet (el archivo .pkpass) es un ZIP firmado, no un formato de documento. Wallet no muestra un pase inválido con una advertencia: se niega a añadirlo, y por eso la mayoría de la gente conoce este formato mirando un pase que simplemente no abre. Esta guía construye uno a partir de sus cuatro partes obligatorias y luego cubre los fallos que provocan un rechazo silencioso.
Apple también ofrece Pass Designer para diseñar pases de forma visual, y puedes usarlo para prototipar el diseño. Cuando el pase lo debe generar un servidor, en cambio, construyes el archivo tú mismo.
01Qué contiene realmente un archivo .pkpass
Renombra cualquier pase que funcione a .zip, descomprímelo y encontrarás estas piezas:
| Archivo | ¿Obligatorio? | Función |
|---|---|---|
pass.json | Sí | Definición del pase: identificadores, estilo, colores, código, campos |
manifest.json | Sí | Hash SHA-1 de cada uno de los demás archivos |
signature | Sí | Firma PKCS#7 separada de manifest.json |
icon.png, icon@2x.png | Sí | El icono pequeño que muestra Wallet |
logo.png, strip.png, miniaturas | Según estilo | Arte opcional, con los tamaños de Apple |
El manifest es la capa de integridad, y los pasos de compilación de Apple lo mantienen deliberadamente simple: un objeto JSON plano que asigna la ruta de cada archivo de origen a su digest SHA-1 en hexadecimal. Nunca se incluye a sí mismo ni a la firma, y tampoco debe listar metadatos como .DS_Store.
{
"icon.png": "6c4f1b2a4e2b7d3c9a5f8e1d0b6a3c2e4f5a6b7c",
"logo.png": "b1d2c3e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8b9c0",
"pass.json": "9f8e7d6c5b4a39281706f5e4d3c2b1a09f8e7d6c"
}
El manifest debe coincidir exactamente con el ZIP
Si
manifest.jsonlistalogo@2x.pngy ese archivo no existe, o si hay un archivo en el ZIP que no aparece en el manifest, la validación de la firma falla y Wallet rechaza el pase. Regenera el manifest después de cada cambio de imagen.
02Construye pass.json para los cinco estilos
Todos los pases comparten unas claves superiores y luego declaran exactamente un estilo. Las claves comunes son formatVersion (siempre 1), passTypeIdentifier, serialNumber, teamIdentifier, organizationName y description. Si tu servidor publica actualizaciones, también necesitas webServiceURL y authenticationToken.
El diccionario de estilo es uno de generic, storeCard, coupon, eventTicket o boardingPass. Cada estilo expone regiones distintas: un pase de embarque tiene primaryFields, secondaryFields, auxiliaryFields y backFields en posiciones fijas, mientras que un pase genérico usa las mismas regiones con otra intención.
Los campos tienen tope. En general un pase admite hasta tres campos de cabecera, un campo primario, cuatro secundarios y cuatro auxiliares; un pase de embarque permite dos primarios y cinco auxiliares, y los cupones, tarjetas de fidelización y pases genéricos con código cuadrado comparten cuatro campos secundarios y auxiliares entre ellos. (Guía de PassKit)
{
"formatVersion": 1,
"passTypeIdentifier": "pass.com.example.loyalty",
"serialNumber": "member-8842",
"teamIdentifier": "ABCDE12345",
"organizationName": "Example Coffee",
"description": "Example Coffee loyalty card",
"backgroundColor": "rgb(67, 56, 202)",
"foregroundColor": "rgb(255, 255, 255)",
"labelColor": "rgb(224, 231, 255)",
"storeCard": {
"primaryFields": [
{ "key": "balance", "label": "Balance", "value": 12.5, "currencyCode": "USD" }
],
"secondaryFields": [
{ "key": "tier", "label": "Tier", "value": "Gold" }
]
},
"barcodes": [
{ "format": "PKBarcodeFormatQR", "message": "member-8842", "messageEncoding": "iso-8859-1" }
]
}
Dos detalles se escapan siempre. Los colores usan la forma de cadena rgb(r, g, b), no hexadecimal ni un array. Y serialNumber es la identidad del pase: reutilizarlo para otro socio sobrescribe la tarjeta equivocada cuando empujas una actualización.
03Genera el manifest y la firma PKCS#7
La firma es el paso que no se puede simular. Necesitas el certificado Pass Type ID y su clave privada desde tu cuenta de desarrollador, más el certificado intermedio WWDR de Apple.
- Calcula el hash de cada archivo salvo el manifest y la firma. Ejecuta esto dentro del directorio del pase:
for f in $(find . -type f ! -name 'manifest.json' ! -name 'signature' -maxdepth 1 | sed 's|^\./||'); do
printf ' "%s": "%s",\n' "$f" "$(shasum -a 1 "$f" | cut -d' ' -f1)"
done
- Monta
manifest.jsoncon esas líneas. Debe ser JSON válido y sin coma final tras la última entrada; el bucle anterior deja una coma a propósito, así que quítala o genera el archivo con un script. - Firma el manifest, no los archivos individuales:
openssl smime -binary -sign \
-certfile WWDR.pem \
-signer passcert.pem \
-inkey passkey.pem \
-in manifest.json \
-out signature \
-outform DER
- Comprime el directorio sin carpeta padre y sin metadatos de macOS:
zip -r example.pkpass . -x '.*' -x '__MACOSX' -x '.*/'
- Verifica antes de publicar. La firma debe validar contra el manifest que realmente empaquetaste:
openssl smime -verify -in signature -inform DER -content manifest.json -noverify
Si ese comando imprime Verification successful, la mitad criptográfica está lista.
04Añade las imágenes con los tamaños que Wallet espera
Wallet escala y después recorta el arte que le das, así que el número que importa es el espacio asignado a cada imagen, medido en puntos. Las imágenes que no encajan en su espacio se escalan y se recortan, y icon.png es obligatorio.
| Imagen | Espacio asignado | Notas |
|---|---|---|
icon.png | 29 × 29 puntos | Obligatorio; también se usa en la pantalla bloqueada y en Mail |
logo.png | 160 × 50 puntos | Normalmente más estrecho que el espacio disponible |
strip.png | 375 × 123 puntos | 375 × 144 para tarjetas de fidelización y cupones, 375 × 98 para entradas de eventos |
thumbnail.png | 90 × 90 puntos | Mantén la proporción entre 2:3 y 3:2 |
background.png | 180 × 220 puntos | Se recorta ligeramente por los cuatro lados y se difumina |
Un punto equivale exactamente a un píxel en una pantalla no Retina y a dos o tres píxeles en una Retina, así que incluye el archivo base más las variantes @2x y @3x. (Guía de PassKit)
Regenera el manifest al final
Edita las imágenes, luego reconstruye
manifest.json, después firma y por último comprime. Cualquier otro orden deja hashes obsoletos y produce un pase que parece terminado pero falla la validación.
05Reglas del código que fallan en silencio
El código es donde el pase deja de ser un ejercicio de diseño. Los escáneres y el software de códigos de barras suelen esperar ISO 8859-1 (Latin-1) o Windows-1252, y la mayoría de los sistemas soporta mal Unicode, así que un message con emoji o con un nombre no latino es el fallo silencioso clásico. Mantén la carga del código en ASCII y pon el texto legible en un campo.
| Síntoma | Causa | Solución |
|---|---|---|
| El pase se añade pero el código sale vacío | Falta el array barcodes o está vacío | Añade al menos una entrada con format válido |
| El código muestra texto corrupto | message no es ISO 8859-1 ni Windows-1252 | Usa ASCII en message y mueve el texto a un campo |
| El código no aparece en el Apple Watch | Solo hay Code 128, y watchOS no lo admite | Añade una entrada QR o PDF 417 como respaldo |
| Un iPhone antiguo no muestra el código | Solo está la clave antigua barcode | Emite también barcodes; el array se usa desde iOS 9 |
Wallet admite QR, PDF 417, Aztec, Code 128, Code 39, Codabar, EAN 13 e ITF, y PassKit usa la primera entrada compatible del array. QR, PDF 417, Aztec y Code 128 son válidos desde iOS 9, así que esos cuatro no necesitan respaldo. El QR es la opción más segura para el poco espacio que ofrece una pantalla. (Códigos, Guía de PassKit)
Cuanto más corta la carga, mejor
Cada formato tiene un máximo teórico y las condiciones reales de escaneo lo reducen: el ejemplo de la guía es un código en el Apple Watch, con poca luz y un escáner barato. Prueba con el hardware que se usará realmente.
06Prueba en un dispositivo y planifica las actualizaciones
La prueba que documenta Apple es arrastrar el pase a un iPhone del simulador, que muestra el diálogo de añadir si el pase es válido; antes de enviarlo a clientes, recorre el flujo completo de añadir a Wallet en un dispositivo real. Envía el archivo por AirDrop o sírvelo desde HTTPS con el tipo MIME application/vnd.apple.pkpass para que Safari ofrezca el botón de añadir. (Technical Note TN2302)
Si el pase cambia tras emitirse —un saldo, una puerta, una hora de embarque— no lo reconstruyes en el dispositivo. Añades webServiceURL y authenticationToken a pass.json, el dispositivo se registra en tu servidor y entrega un token push, y más tarde tu servidor envía una notificación push que hace que el dispositivo descargue el pase actualizado. Por eso authenticationToken debe ser largo y aleatorio: es el secreto compartido que autentica cada llamada a tus endpoints de actualización.
07Errores comunes y soluciones
| Error | Causa probable | Solución |
|---|---|---|
| «No se puede añadir el pase», sin detalle | El manifest y la firma no coinciden | Reconstruye el manifest, firma y comprime de nuevo |
| La firma valida pero Wallet rechaza | passTypeIdentifier no coincide con el certificado | Usa el Pass Type ID exacto del portal |
| El pase aparece sin estilo | Colores en hexadecimal | Usa cadenas rgb(r, g, b) |
| La actualización nunca llega | serialNumber erróneo o token caducado | Usa seriales únicos y estables por pase |
El patrón tras casi todos los fallos es el mismo: Wallet trata el pase como un artefacto firmado, así que cambiar cualquier byte —incluido volver a guardar una imagen— invalida la firma. Escribe un script que regenere el manifest, firme y comprima en un solo comando y dejarás de depurar hashes a mano.
08Fuentes
- Building a Pass — https://developer.apple.com/documentation/walletpasses/building-a-pass (fecha de consulta: 2026-10-09)
- Creating a Pass with Pass Designer — https://developer.apple.com/documentation/walletpasses/creating-a-pass-with-pass-designer (fecha de consulta: 2026-10-09)
- Pass — https://developer.apple.com/documentation/walletpasses/pass (fecha de consulta: 2026-10-09)
- PassKit Programming Guide: Creating Passes — https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html (fecha de consulta: 2026-10-09)
- Barcodes — https://developer.apple.com/documentation/walletpasses/pass/barcodes (fecha de consulta: 2026-10-09)
- Technical Note TN2302: Passbook FAQ — https://developer.apple.com/library/archive/technotes/tn2302/_index.html (fecha de consulta: 2026-10-09)
- Adding a Web Service to Update Passes — https://developer.apple.com/documentation/walletpasses/adding-a-web-service-to-update-passes (fecha de consulta: 2026-10-09)
Valida y formatea pass.json antes de calcular hashes: una coma de más arruina el pase entero.
Suite JSON multipropósitoPreguntas frecuentes
¿Por qué mi .pkpass no se añade a Apple Wallet?
Nueve de cada diez veces la firma no coincide con el manifest, o el manifest lista un archivo que no está en el ZIP. En ambos casos Wallet rechaza el pase en silencio.
¿Puedo crear un pase de Wallet sin cuenta de desarrollador de Apple?
No. La firma requiere un certificado Pass Type ID emitido desde tu cuenta de desarrollador. Puedes preparar el JSON y las imágenes, pero Wallet no aceptará un pase sin firmar.
¿El manifest usa SHA-1 o SHA-256?
El formato del manifest calcula SHA-1 sobre cada archivo del paquete, algo independiente del debate sobre usar SHA-1 o SHA-256 como hash de objetos en Git.
¿Por qué desaparece el código en el Apple Watch?
watchOS no admite Code 128. Si Code 128 es la única entrada del array barcodes, el reloj no muestra ningún código, así que añade una entrada QR o PDF 417 como respaldo.
¿Por qué no se escanea mi código de barras?
Normalmente la carga no coincide con lo que espera el escáner: el hardware de códigos de barras suele leer ISO 8859-1 o Windows-1252, y soporta mal Unicode. Mantén el message en ASCII y mueve el texto legible a un campo.
Artículos relacionados
- Cómo formatear, validar y minificar JSON
pass.json es JSON estricto: las reglas que rompen una API también rompen un pase.
- Crea un código QR que siempre se escanee
Corrección de errores, zona de silencio y tamaño para el código del pase.
Herramientas relacionadas
- Formateador JSON
Embellece y reindenta pass.json.
- Validador JSON
Detecta la coma sobrante antes de firmar.
- Codificador / decodificador Base64
Inspecciona cargas codificadas y datos de códigos.