1. What is a .pkpass file?
A .pkpass file is a digitally signed package that delivers a single pass to Apple Wallet — the iPhone, iPad, Apple Watch and Mac app where users keep boarding passes, event tickets, coupons, loyalty cards, hotel keys, transit cards and similar credentials. Apple introduced the format on 11 June 2012 at WWDC under the name Passbook, and shipped it three months later in iOS 6 on 19 September 2012. It was renamed Apple Wallet with iOS 9 in September 2015, a year after Apple Pay launched in iOS 8.1 — consolidating both passes and payment cards under a single Wallet brand. The underlying file format and developer framework — PassKit — has stayed compatible the whole way through.
Mechanically, a .pkpass is a ZIP archive renamed to use the .pkpass extension. Inside it are a JSON file called pass.json that describes the pass, a few PNG images, a manifest.json with SHA-1 hashes of every other file, and a signature file that proves the pass came from a registered Apple Developer team. The MIME type is application/vnd.apple.pkpass — Apple Mail, Safari and most modern email apps key off that to trigger the "Add to Apple Wallet" preview when a user taps the attachment.
The format is open in structure and closed in trust: the data is JSON and PNGs documented in Apple's Wallet Developer Guide, but a PKCS#7 signature ties every pass back to a Pass Type ID certificate issued to a single Apple Developer team. Anyone can read a .pkpass, but only that team can produce a new one Wallet will install.
Issuers — airlines, venues, retailers, transit agencies, hotels, employers — generate a .pkpass on their backend and send it to the customer over email, an SMS link, or a custom app. The customer taps it, Wallet renders a preview, and one tap later it lives on their device. From there, Apple Wallet can keep the pass up to date over a push channel, surface it on the lock screen at the right time and place, and (for boarding passes and tickets) hand it to the Apple Watch or to NFC readers automatically.
If you don't yet have a pass to look at, you can make one in under a minute from any barcode and follow along with everything below.
2. .pkpass file format
A .pkpass is a standard PKZip archive. You can rename example.pkpass to example.zip and any zip tool will list and extract its contents. The archive must contain the pass files at its root — wrapping them in a folder is the most common reason a hand-crafted pass fails to install. Inside, the file set is small and predictable.
| File | Required? | Purpose |
|---|---|---|
pass.json | Yes | The pass itself — fields, colors, barcode, identifiers. |
manifest.json | Yes | SHA-1 hash of every other file, keyed by relative path. |
signature | Yes | PKCS#7 detached signature over manifest.json. |
icon.png (+ @2x, @3x) | Yes | Shown in notifications and on the back of the pass. |
logo.png (+ @2x, @3x) | Recommended | Pass header logo, top-left of the front face. |
strip.png (+ @2x, @3x) | Style-dependent | Full-width banner on coupons, store cards, tickets. |
thumbnail.png (+ @2x, @3x) | Style-dependent | Square image on event tickets and generic passes. |
background.png (+ @2x, @3x) | Optional | Blurred background on event tickets only. |
footer.png (+ @2x, @3x) | Boarding pass | Image directly above the barcode. |
{lang}.lproj/ | Optional | Per-locale string overrides and localized images. |
Image dimensions
Apple gives image sizes in points; @2x means 2 pixels per point, @3x means 3. Most issuers ship 1×, @2x and @3x assets so the pass looks crisp on every screen from a Watch to a Pro Max. The canonical sizes from Apple's Pass Design and Creation guide are:
| Image | 1x (points) | @2x (pixels) | @3x (pixels) |
|---|---|---|---|
icon | 29 × 29 | 58 × 58 | 87 × 87 |
logo | up to 160 × 50 | up to 320 × 100 | up to 480 × 150 |
thumbnail | 90 × 90 | 180 × 180 | 270 × 270 |
strip (event ticket) | 375 × 98 | 750 × 196 | 1125 × 294 |
strip (coupon, store card) | 375 × 144 | 750 × 288 | 1125 × 432 |
background | 180 × 220 | 360 × 440 | 540 × 660 |
footer | 286 × 15 | 572 × 30 | 858 × 45 |
Images are PNG, sRGB, with an alpha channel where transparency matters (icon, logo). Apple has historically been strict about exact dimensions for strip images on coupons; off-by-a-few-pixels can produce ugly cropping but usually still installs.
MIME type, extension, encoding
- Extension:
.pkpassfor a single pass;.pkpassesfor a bundle of multiple passes. - MIME type:
application/vnd.apple.pkpass(single) orapplication/vnd.apple.pkpasses(bundle). - Character encoding: JSON files are UTF-8. Localized
pass.stringsfiles must be UTF-16 if they contain any non-ASCII character — Apple's tooling will silently misread UTF-8 strings files.
Localization
To support multiple languages, an issuer adds {lang}.lproj/ subdirectories — for example en.lproj/, fr.lproj/, ja.lproj/. Each contains a pass.strings key/value file with translations and, optionally, replacement images. At display time iOS picks the closest available locale to the device language. Apple's one strict rule: don't put an image at the top level and in an .lproj with the same name — that produces undefined behavior.
3. Inside pass.json
pass.json is where almost every interesting decision about a pass lives — what it looks like, what data it shows, where it surfaces, and how it updates. The schema is documented in Apple's PassKit Bundle Reference, and it has stayed remarkably stable since 2012.
Top-level keys
Six keys are required on every pass; everything else is optional but useful.
| Key | Type | Required | Notes |
|---|---|---|---|
formatVersion | integer | Yes | Always 1. |
passTypeIdentifier | string | Yes | Reverse-DNS, must match the signing certificate's UID. |
serialNumber | string | Yes | Unique within a pass type. Case-sensitive. |
teamIdentifier | string | Yes | 10-character Apple Team ID. Must match the cert's OU. |
organizationName | string | Yes | Shown in notifications and the lock screen. |
description | string | Yes | Used by VoiceOver. Localizable. |
logoText | string | No | Plain text rendered next to the logo. |
foregroundColor / backgroundColor / labelColor | string | No | CSS-style rgb(r, g, b). Hex is silently ignored. |
expirationDate | ISO 8601 | No | After this moment Wallet shows the pass as expired and stops surfacing it on the lock screen, but does not auto-delete it. |
relevantDate | ISO 8601 | No | A single point in time when the pass should surface on the lock screen. Window varies by style (boarding pass: ~1 hour before). |
voided | boolean | No | Permanently invalidates the pass. |
locations | array | No | Up to 10 latitude/longitude entries. The pass surfaces on the lock screen near any of them. |
beacons | array | No | Up to 10 iBeacon UUID/major/minor entries. |
maxDistance | number | No | Override the default geofence radius (in metres) around locations. |
groupingIdentifier | string | No | Boarding passes and event tickets only. Passes sharing this string collapse into a stack. |
sharingProhibited | boolean | No | When true, prevents the user from sharing the pass via AirDrop or Messages. |
associatedStoreIdentifiers / appLaunchURL | array / string | No | Promote a companion iOS app from the back of the pass. |
barcodes | array | No | iOS 9+ array; first compatible entry is shown. Older barcode singular is deprecated but still honored. |
webServiceURL + authenticationToken | string | No | Endpoint Apple's push system can call to update the pass. |
nfc | dict | No | NFC payload for tap-to-redeem. Restricted to Apple's Wallet for Business / VAS partners. |
semantics | dict | No | Structured metadata (flight, event, transit) for Siri, Watch and lock-screen logic. |
boardingPass / eventTicket / coupon / storeCard / generic | dict | One of, required | Holds the field groups for the chosen pass style. |
Field groups
Inside the chosen style dictionary, fields are organized into five arrays: headerFields, primaryFields, secondaryFields, auxiliaryFields and backFields. Each is a list of field dictionaries. Header fields appear top-right of the pass and are visible even when the pass is folded into the Wallet stack; primary fields are large and central; secondary and auxiliary are the small label/value pairs in a row underneath; back fields are everything you see when you tap the i on the back of the card.
A field dict needs key (unique within the pass) and value; everything else — label, alignment, date and number formatting, changeMessage, dataDetectorTypes, attributed values with HTML — is optional. Date fields use ISO 8601 strings and are formatted on-device according to dateStyle, timeStyle and the user's locale.
Back fields are special in two ways: their value strings are scanned for URLs, phone numbers, dates and addresses and rendered as tappable links by default — override per field with dataDetectorTypes: [] — and they support attributedValue containing a small subset of HTML, of which <a href> is the most useful because it lets you label a tappable URL with display text different from the URL itself. Back fields are the only place on a pass where the user can tap content.
Barcodes
A barcode dictionary has four keys: format, message, messageEncoding and optional altText. The four supported formats are PKBarcodeFormatQR, PKBarcodeFormatPDF417, PKBarcodeFormatAztec and PKBarcodeFormatCode128. The 2D formats (QR, PDF417, Aztec) were added in iOS 9 alongside the new barcodes array; before iOS 9 the singular barcode key with Code 128 was the only mechanism. Code 128 is a 1D linear barcode and is not rendered on Apple Watch, so Watch-bound passes must pick QR, PDF417 or Aztec. messageEncoding is required and is typically iso-8859-1; use utf-8 when the payload contains characters outside Latin-1.
Colors
Apple's color parser only accepts the CSS function form rgb(R, G, B) with integer 0-255 components. #RRGGBB, rgba() and named colors are silently ignored, leaving Wallet to fall back to defaults. This is one of the most common reasons a pass installs but looks wrong: a designer pasted a hex value and the parser quietly defaulted to black on white.
Semantic tags
Since iOS 12, the optional semantics dict carries structured metadata that iOS uses for Siri suggestions, lock-screen relevance and Apple Watch awareness. For a flight, that's airlineCode + flightNumber + departureAirportCode + currentDepartureDate; for an event, eventName + venueLocation + eventStartDate; for a transit pass, transitProvider + departureStationName + currentDepartureDate. Wallet uses these to bind a boarding pass to Apple's flight tracker without any web service work from the issuer.
4. How signing works
The signature is what separates a real pass from a tampered or forged one. Here's the chain of trust, top to bottom:
- Apple Root CA — Apple's offline root, embedded in iOS, macOS and watchOS trust stores.
- Apple Worldwide Developer Relations (WWDR) intermediate — Apple has rotated this intermediate several times. Generations G2 through G6 are all currently issued and valid for different cert types; Pass Type ID certificates have for years chained through the original WWDR (and now newer generations as Apple rotates). The signature must bundle whichever WWDR generation the Pass Type ID cert chains through. Older tutorials hard-code an expired intermediate — if signing fails, re-download the WWDR cert that matches your Pass Type ID's generation from apple.com/certificateauthority.
- Pass Type ID certificate — issued to a single Apple Developer team, bound to a single reverse-DNS pass type identifier (e.g.
pass.com.example.coupon). This is the leaf cert whose private key signs each pass.
Each Pass Type ID cert encodes the pass type identifier as the UID in its subject and the team's 10-character Team ID as the OU. Apple Wallet checks both at install time.
The signing procedure
From Apple's official guide, the steps are:
- Build the unsigned pass package:
pass.jsonplus all images, in a directory. - Recursively walk the directory, compute the SHA-1 of every file's contents, and write the result to
manifest.jsonas a JSON object that maps each relative path to its SHA-1 hex digest — e.g."icon.png"→"abc123…","pass.json"→"def456…". Do not includemanifest.jsonorsignaturethemselves. - Make a PKCS#7 detached signature over the bytes of
manifest.json, using the Pass Type ID cert's private key. Bundle the matching WWDR intermediate certificate in the signature so Wallet can build a chain to the Apple root, and carry the S/MIMEsigning-timeattribute. - ZIP the contents of the pass directory (not the directory itself) into a file with a
.pkpassextension.
Most reference implementations use OpenSSL for the signature step:
openssl smime -binary -sign \
-certfile WWDR.pem \
-signer passcert.pem \
-inkey passkey.pem \
-in manifest.json \
-out signature \
-outform DER
Apple also ships a small Objective-C tool called signpass in the Wallet Companion Files archive that wraps the same logic.
What iOS validates
When a user opens a .pkpass, Apple Wallet runs roughly this check:
- Parse the ZIP; load
manifest.json,signatureandpass.json. - Verify the PKCS#7 detached signature over
manifest.json's exact bytes. - Build a certificate chain from the leaf through the bundled WWDR intermediate to Apple Root CA, and check the leaf is not expired or revoked.
- Re-hash every file in the bundle and confirm each digest matches the value in
manifest.json. - Confirm
passTypeIdentifierinpass.jsonequals the leaf cert'sUID, andteamIdentifierequals the cert'sOU.
Any failure produces a generic install error; iOS does not tell the user (or the developer) which step failed. This is why almost every "this pass cannot be installed" debugging session starts with verifying the manifest hashes and the cert chain.
Why you can't re-sign someone else's pass
The Pass Type ID certificate is bound at issuance to one team and one identifier. Apple won't issue a cert for someone else's identifier, and changing passTypeIdentifier in pass.json to one you do own breaks the manifest and the per-pass push update channel keyed on it. So even with the original .pkpass in hand, you can't re-sign a third party's pass under your own cert and have it install — by design.
5. How to open a .pkpass file
Where you can open a .pkpass — and what features survive — depends on the platform.
Open a .pkpass file on iPhone, iPad and Apple Watch
The native experience. Tap the .pkpass attachment in Mail, Messages, Safari or Files: iOS recognizes the MIME type, opens a full-screen Wallet preview and offers an Add button. Once added, the pass syncs automatically to a paired Apple Watch. From iOS 27 (shipping September 2026), Apple Wallet will also include a built-in Create a Pass button that lets users wrap any QR code in a pass without a developer account — we cover that here.
Open a .pkpass file on Mac
macOS doesn't have a Wallet app — Wallet on Mac is only a settings panel for Apple Pay cards. But double-clicking a .pkpass in Finder opens a private system app called Pass Viewer (/System/Library/CoreServices/Pass Viewer.app) that renders the pass and offers Add to Apple Wallet. The Add action sends the pass to the user's iCloud account; it then shows up on every iPhone, iPad and Apple Watch signed into the same Apple ID. The Mac itself never stores the pass locally. Safari on macOS does the same when you tap an "Add to Apple Wallet" button on a website.
Open a .pkpass file on Android
Apple Wallet isn't available on Android, but you can still open a .pkpass file on Android five different ways as of 2026:
- Google Wallet (native, partial). Since April 2024 Google Wallet on Android can import .pkpass files directly: tap the file in your file manager, Gmail or browser, and the share sheet offers Add to Google Wallet. Rollout is region-gated, and websites that detect your user-agent often won't even offer the file to an Android browser. As an alternative, you can use our PKPASS to Google Wallet converter on any device to mint a save link.
- Pass2U Wallet (
com.passesalliance.wallet). The most popular third-party option, last updated January 2026. Imports .pkpass, pollswebServiceURLfor updates, can backup to Google Drive, has a built-in pass designer. - WalletPasses (
io.walletpasses.android). Long-running, no ads, supports geofence and iBeacon notifications. Last updated June 2025. - FossWallet (
nz.eloque.foss_wallet). The actively maintained open-source option as of 2026, GPL-3.0, on F-Droid. Successor to PassAndroid (which is no longer reliably installing modern passes). - PassWallet (
com.attidomobile.passwallet). The original third-party option; still maintained but the UI shows its age.
On any of these, NFC value-added-services (Apple-Pay-style tap), Apple Watch sync and Express Mode are unavailable. Auto-updates are polled rather than pushed via APNs.
Open a .pkpass file on Windows, Linux and ChromeOS
No native handler. Three good paths:
- Browser-based viewer. Drop the file into our PKPASS Viewer — it parses everything client-side and shows the card preview, every field and the raw
pass.json. - Convert to PDF. Use our PKPASS to PDF converter for a printable A4 with the barcode re-rendered at print resolution.
- Treat it as a ZIP. Rename to
.zip(Windows) or rununzip pass.pkpass(Linux/macOS) and inspect the files directly. Useful when you only want to readpass.json.
On ChromeOS, the Android subsystem makes Pass2U / WalletPasses the easiest install if you want full read-and-update support. Otherwise, the browser viewer route works on every Chromebook.
6. Pass styles
Every .pkpass is one of five styles, declared by which top-level key is present in pass.json. The style controls layout, which images are used, and what surfaces the pass on the lock screen.
| Style | Required extras | Strip | Background | Thumbnail | Footer |
|---|---|---|---|---|---|
boardingPass | transitType (Air, Train, Bus, Boat, Generic) | — | — | — | Yes |
eventTicket | — | Optional | Optional | Yes | — |
coupon | — | Yes | — | — | — |
storeCard | — | Optional | — | — | — |
generic | — | — | — | Yes | — |
Behavioural notes:
- boardingPass renders the origin and destination as oversized primary fields with a chevron between them, with the footer image directly above the barcode. Multiple passes that share a
groupingIdentifiercollapse into a stack. - eventTicket has two presentations: a full-bleed (heavily blurred)
background.pngwith a thumbnail and circular barcode, or astrip.pngacross the top with no thumbnail. Apple recommends not mixing both. - coupon is dominated by the strip image; primary text overlays it.
suppressStripShinematters most here for modern, flat designs. - storeCard typically shows a balance as the primary field. When
nfcis present, Wallet's tap-to-redeem UI lives here. - generic is the fallback layout: small logo and thumbnail on the right, primary field beside the logo. Use it for membership cards, badges, anything that doesn't fit a more specific style.
7. Errors and troubleshooting
Apple Wallet's install errors are intentionally generic: "This pass cannot be installed on iPhone", "This pass is not valid", "Couldn't add the pass". They all mean the same thing — one of the validation steps in section 4 failed — but iOS doesn't say which. The usual suspects, ordered by frequency:
| Symptom / message | Likely cause | Fix |
|---|---|---|
| Install fails immediately, signature does not verify | The bundled WWDR intermediate doesn't match the generation of your Pass Type ID | Download the matching WWDR intermediate from Apple's PKI page and re-sign |
| Install fails, signature OK but manifest mismatch | A file was modified after the manifest was generated — common culprits: re-encoded PNGs, added BOM, line-ending change, .DS_Store dropped in | Re-hash every file and rebuild manifest.json |
| "Pass type identifier doesn't match the certificate" | passTypeIdentifier in pass.json ≠ the leaf cert's UID; or teamIdentifier ≠ the cert's OU | Match both fields exactly to the cert |
| Install OK but pass colors look wrong | Used hex or #RRGGBB for colors | Switch to rgb(R, G, B) with integer components |
| Install OK in Safari, fails in Chrome iOS | Server returns wrong Content-Type or sends as POST | Serve as application/vnd.apple.pkpass over GET |
| "Pass is no longer valid" | voided: true in pass.json, or the leaf cert expired | Reissue the pass (and the cert if needed) |
| ZIP unexpectedly contains a folder | Whoever built it zipped the directory instead of its contents | Zip the contents, not the wrapping directory |
When in doubt, drop the pass into the PKPASS Viewer — it will surface whether the bundle even parses, whether the signature is present, whether pass.json validates, and which images are bundled. Most failed-to-install passes still parse fine in the viewer, which narrows the problem to signing.
8. Creating a .pkpass
You have three practical paths to create a .pkpass.
- Use a hosted tool like WalletWallet. The simplest, fastest, free path: drop a barcode (or a photo of one), pick colors, get a signed
.pkpassback. Try it. We sign each pass with our own Pass Type ID certificate, so installs work on any iPhone, iPad, Watch and Mac without you doing anything with the Apple Developer Program. Full free-pass guide. - Roll your own with Apple's tools. Register a Pass Type ID in the Apple Developer portal (US$99/year membership), download a Pass Type ID certificate plus the matching WWDR intermediate from Apple's PKI page, write your own
pass.json, generate the manifest and signature with OpenSSL or Apple'ssignpasstool, and ZIP. Mature language-specific libraries —passkit-generator(Node),alvinbaena/passkit(Go),applepassgenerator(Python),walletkit(Rust) — handle the manifest hashing and PKCS#7 signing steps for you. - Use a hosted issuer platform. Passcreator, PassNinja, Passslot and similar services let you template a pass, plug in your own cert, and POST values to mint signed passes. Useful when you want push updates and an API but don't want to operate the cert renewal yourself.
A pass is "free" to host but not free to issue at scale: the Apple Developer Program membership is US$99/year per team, certs renew annually, and APNs push for pass updates is free but rate-limited.
9. Frequently asked questions
Are .pkpass files safe to open?
A .pkpass is just a ZIP of JSON and PNGs — no executable code runs on your device when you add one to Wallet. The signature only proves which Apple Developer team issued the pass, not that the pass is benign. The usual scam vector isn't malware, it's social engineering: a phishing email with a fake boarding pass that links to a credential-harvesting site. Treat .pkpass attachments with the same skepticism as any link.
Can I edit a .pkpass after I receive it?
Not in any way Apple Wallet will accept. The signature covers manifest.json, which covers every other file, so changing one byte invalidates the whole bundle. You can read everything inside (rename to .zip, or use a viewer), but installing an edited version requires a fresh signature from a Pass Type ID certificate.
What's the maximum size of a .pkpass?
Apple doesn't publish a hard limit. In practice, passes stay well under 1 MB because the assets are small; HTTPS download timeouts and email gateways become the practical ceiling. The 10 KB limit you see in some third-party docs refers to push update payloads through specific issuer relays, not the file itself.
Can a .pkpass auto-update?
Yes, when the issuer includes a webServiceURL and an authenticationToken (minimum 16 characters). Apple Wallet registers the pass with the issuer, the issuer pushes an empty APNs notification when something changes, and Wallet pulls the new pass over HTTPS. A field generates a user-visible lock-screen notification only if its dictionary includes a changeMessage template (e.g. "Gate changed to %@"); without it the pass updates silently. If the push or HTTPS pull fails, Wallet retries on its own backoff and the user keeps seeing the cached version — there is no failure UI. Common use: gate changes on a boarding pass, balance updates on a store card, hotel key revocation.
Why are .pkpass files signed with SHA-1 in 2026?
Backwards compatibility. Apple introduced PassKit on iOS 6 in 2012 with SHA-1 manifests, and SHA-1 remains the documented and most-supported algorithm. The integrity property still holds because the PKCS#7 signature covers the manifest as a whole and uses modern signing algorithms — a SHA-1 collision on an individual file would still have to satisfy the signed manifest.
Is .pkpass the same as .pkpasses?
Almost. .pkpass is a single pass; .pkpasses is a bundle of multiple passes in one ZIP, used when an issuer wants to deliver, say, a parent and child boarding pass together. Apple Wallet shows a stack and adds them all in one tap.
Tools and further reading
- PKPASS Viewer →
Inspect any .pkpass in your browser — fields, images, barcode, raw
pass.json. - PKPASS to PDF Converter →
Drop a .pkpass, get a printable A4 PDF with a scannable barcode.
- PKPASS to Google Wallet Converter →
Mint a one-tap Google Wallet save link from any .pkpass.
- How to Create an Apple Wallet Pass for Free →
The full guide to going from a barcode to a signed .pkpass without a developer account.
- iOS 27 Adds a Built-in Create-a-Pass Button →
What Apple's native pass builder will and won't do when iOS 27 ships.