pass.json, key by key.
The six keys Wallet requires, the style key that holds your fields, and everything optional, with the file a real pass ships.
pass.json is the file inside a .pkpass that says what the pass is: its identifiers, its style, its fields, its barcode and how it updates. Six top-level keys are required, plus exactly one style key.
- Required
- formatVersion, passTypeIdentifier, serialNumber, teamIdentifier, organizationName, description.
- One style key
- boardingPass, coupon, eventTicket, generic or storeCard, holding the fields.
- Must match the certificate
- passTypeIdentifier and teamIdentifier are checked against the signing certificate.
The top-level keys.
| Key | Type | Required | What it does | Cardr sets it |
|---|---|---|---|---|
description |
string | Yes | What the pass is, for VoiceOver. Short and specific. | Yes |
formatVersion |
number | Yes | Always the number 1. A string "1" is refused. | Yes |
organizationName |
string | Yes | Shown on the lock screen and in Mail. | Yes |
passTypeIdentifier |
string | Yes | Must match the Pass Type ID in the signing certificate. | Yes |
serialNumber |
string | Yes | Unique within the pass type. The update service keys on it. | Yes |
teamIdentifier |
string | Yes | Must match the team in the signing certificate. | Yes |
boardingPass |
dictionary | No | Needs transitType. | |
coupon |
dictionary | No | Style (exactly one) | |
eventTicket |
dictionary | No | Strip or background layout, never both. | |
generic |
dictionary | No | Style (exactly one) | |
storeCard |
dictionary | No | Style (exactly one) | Yes |
barcodes |
array of dictionaries | No | The first format the device supports is used. | Yes |
barcode |
dictionary | No | Deprecated. Kept only for very old iOS alongside barcodes. | |
backgroundColor |
string, rgb(r, g, b) | No | Visual | Yes |
foregroundColor |
string, rgb(r, g, b) | No | Field values. | Yes |
labelColor |
string, rgb(r, g, b) | No | Field labels. | Yes |
logoText |
localizable string | No | Beside the logo. | Yes |
suppressStripShine |
boolean | No | Turns off the gloss on a strip image. | Yes |
groupingIdentifier |
string | No | Event tickets and boarding passes only: groups related passes. | |
expirationDate |
W3C date string | No | After it, the pass is shown as expired. | |
voided |
boolean | No | Expiry | |
relevantDate |
W3C date string | No | When the pass may surface on the lock screen. | |
locations |
array of dictionaries | No | Up to ten. | |
beacons |
array of dictionaries | No | Relevance | |
maxDistance |
number (metres) | No | Relevance | |
webServiceURL |
string (https) | No | Base URL of the update service. HTTPS only in production. | Yes |
authenticationToken |
string | No | At least 16 characters. Sent back as "ApplePass <token>". | Yes |
appLaunchURL |
string | No | Associated app | |
associatedStoreIdentifiers |
array of numbers | No | App Store ids. | |
userInfo |
dictionary | No | For your own app. Wallet ignores it. | |
sharingProhibited |
boolean | No | Sharing | Yes |
nfc |
dictionary | No | Needs an NFC certificate from Apple, granted after a business review. | |
semantics |
dictionary | No | Machine-readable meaning of the pass, for Siri and the system. | |
preferredStyleSchemes |
array of strings | No | iOS 18 poster event ticket. Renders only for NFC-enabled passes. |
Key facts checked against Apple’s Pass reference on 24 September 2026. The last column is generated from the pass Cardr builds today.
The pass.json Cardr ships.
Generated from the code that builds every Cardr pass, for a demo card. The identifiers and token are placeholders; the shape is exact.
{
"formatVersion": 1,
"passTypeIdentifier": "pass.co.example.card",
"teamIdentifier": "ABCDE12345",
"serialNumber": "example-serial",
"organizationName": "Example Ltd",
"logoText": "Example Ltd",
"description": "Business card for Jordan Hale",
"foregroundColor": "rgb(29,29,31)",
"backgroundColor": "rgb(184,184,187)",
"labelColor": "rgb(75,75,80)",
"sharingProhibited": false,
"suppressStripShine": true,
"webServiceURL": "https://cardr.co",
"authenticationToken": "a-token-of-at-least-16-chars",
"storeCard": {
"headerFields": [],
"primaryFields": [],
"secondaryFields": [
{
"key": "role",
"label": "",
"value": "Director"
}
],
"auxiliaryFields": [
{
"key": "phone",
"label": "",
"value": "+44 7700 900123",
"dataDetectorTypes": [
"PKDataDetectorTypePhoneNumber"
]
}
],
"backFields": [
{
"key": "profile",
"label": "Profile",
"value": "https://cardr.co/u/jordan",
"attributedValue": "<a href=\"https://cardr.co/u/jordan\">https://cardr.co/u/jordan</a>"
},
{
"key": "back_email",
"label": "Email",
"value": "jordan@example.com",
"attributedValue": "<a href=\"mailto:jordan@example.com\">jordan@example.com</a>"
},
{
"key": "back_phone",
"label": "Phone",
"value": "+44 7700 900123",
"attributedValue": "<a href=\"tel:+44 7700 900123\">+44 7700 900123</a>"
}
]
},
"barcodes": [
{
"format": "PKBarcodeFormatQR",
"message": "https://cardr.co/u/jordan?c=qr",
"messageEncoding": "iso-8859-1"
}
]
}
pass.json questions.
Which keys does Wallet require?
Six: formatVersion (the number 1), passTypeIdentifier, serialNumber, teamIdentifier, organizationName and description, plus exactly one style key such as storeCard. A pass missing any of them will not open.
Can I add my own keys?
Put your own data in userInfo. Wallet ignores it, and it travels with the pass to your app.
How do I check mine?
Open it in the .pkpass viewer. It points to the line and column of broken JSON and lists missing required keys, in your browser.