Packaging
PKPass manifest and package structure explained
Learn exactly what belongs inside a .pkpass archive, how manifest hashes work, and why wrapper folders and stale assets break validation.
What you’ll leave with
- A .pkpass is a ZIP archive with pass files at its root.
- manifest.json binds filenames to exact bytes; signature binds the manifest to the certificate.
- Localization directories and Retina assets must be covered by the manifest like every other pass resource.
The anatomy of a .pkpass archive
The package is a ZIP archive with a different extension. At minimum, a distributable pass contains pass.json, manifest.json, signature, and the artwork required by its design. Files belong at the archive root; localization resources live in language-specific .lproj directories beneath that root.
ExampleMembership.pkpass
├── pass.json
├── manifest.json
├── signature
├── icon.png
├── [email protected]
├── logo.png
├── [email protected]
└── en.lproj
└── pass.stringsmanifest.json is the byte-level contract
Each manifest key is the relative path of a packaged file and each value is its SHA-1 digest. That digest changes when metadata, compression, color profiles, JSON whitespace, or any other byte changes. Generate hashes from the exact files that will be zipped.
The manifest normally excludes itself and signature. It includes pass.json, images, localized strings, and every other resource the pass relies on. A verifier should reject missing referenced files and mismatched hashes.
How the signature protects the package
The detached PKCS#7 signature covers manifest.json. Because the manifest covers the other files, the signature indirectly protects the complete package. This chain only works when both checks are performed: signature against manifest, and every manifest digest against its file.
This is why changing an image after signing invalidates the pass even though the signature file itself still parses. The manifest no longer describes the current image bytes.
Common packaging errors
Wrapper folders happen when the directory is zipped rather than its contents. Case mismatches happen when development runs on a case-insensitive filesystem but verification is case-sensitive. Hidden macOS metadata adds files that may not belong in the manifest, and duplicate filenames can cause different ZIP libraries to resolve different bytes.
- Archive root is PassFolder/pass.json instead of pass.json
- manifest says icon.png but archive contains Icon.png
- A file was optimized after manifest generation
- Localization path or filename differs from the manifest key
- Archive contains .DS_Store, __MACOSX, or duplicate entries
Put it into practice
Build the JSON, then verify the package.
Use the free browser tools to turn the rules in this guide into a clean starting file and an actionable validation report.
Skip the hand-assembly.
PassMaker does every step on this page on your iPhone — field editor, artwork, manifest, PKCS#7 signing and Add to Wallet — without wiring up a signing environment.
Download on the App StorePrimary references
Related guides
Signing
How to sign a .pkpass file correctlyA focused guide to Pass Type ID certificates, manifest hashing, detached PKCS#7 signatures, WWDR certificates, and final packaging.
9 min readTroubleshooting
Fix “Safari cannot download this file” for PKPassDiagnose the common packaging, signature, MIME type, redirect, and certificate problems that prevent Apple Wallet passes from installing.
7 min readGetting started
How to create an Apple Wallet passA practical end-to-end guide to designing, packaging, signing, testing, and distributing a real Apple Wallet pass.
8 min read