For the complete documentation index, see llms.txt. This page is also available as Markdown.

Wallet - Creating Passes

This page covers the part that happens before you ever call Wallet.addPasses — building and signing the pass itself, on your own backend. WebToNative never creates, edits, or signs a pass; it only hands whatever you give it to the OS wallet app. See Google Wallet / Apple Wallet for the JS API this feeds into.


Google Wallet (Android)

A Google Wallet pass isn't a file you generate once and host — it's a JWT your backend signs on the fly (or a save link built from one), referencing pass data that lives in your Google Wallet Issuer account.

1. Create a Google Wallet Issuer Account

Sign up at the Google Wallet Business Console and get your Issuer ID — every pass class/object you create is scoped to it.

2. Set Up a Service Account

In Google Cloud Console, enable the Google Wallet API, create a service account, and download its JSON key. This key's private key is what signs the JWT in step 4 — keep it server-side only.

3. Define a Pass Class

A class is the reusable template for a pass type — the loyalty program, the event, the flight route. Create it once via the Google Wallet REST API (POST https://walletobjects.googleapis.com/walletobjects/v1/<type>Class), picking the type that matches what you're issuing:

genericClass · loyaltyClass · offerClass · eventTicketClass · flightClass · giftCardClass · transitClass

4. Create a Pass Object

An object is one instance of that class for one specific user — their points balance, their seat, their gift card value. Create it via the matching <type>Object endpoint (e.g. loyaltyObject), referencing the classId from step 3.

5. Build & Sign the Save JWT

To hand a pass to Wallet.addPasses, sign a JWT whose claims are:

Claim
Value

iss

Your service account's email address.

aud

Always "google".

typ

Always "savetowallet".

iat

Issued-at timestamp.

payload

An object keyed by the class/object type, e.g. { "loyaltyObjects": [{ "id": "...", "classId": "..." }] }. Accepted keys: genericClasses/genericObjects, loyaltyClasses/loyaltyObjects, offerClasses/offerObjects, eventTicketClasses/eventTicketObjects, flightClasses/flightObjects, giftCardClasses/giftCardObjects, transitClasses/transitObjects.

Sign with RS256 using the service account's private key.

Requires firebase/php-jwt (composer require firebase/php-jwt).

Handing It to WebToNative

The signed JWT is exactly what Wallet.addPasses expects in passes:

You can also wrap it as https://pay.google.com/gp/v/save/<jwt> and pass that string instead — both are accepted.


Apple Wallet (iOS)

An Apple Wallet pass is a file — a .pkpass, which is really just a signed zip. Unlike Google Wallet, there's no live API call per pass; you build and sign the file, then host it or hand over its bytes.

1. Get a Pass Type ID & Certificates

In your Apple Developer account, register a Pass Type ID (e.g. pass.com.example.loyalty) and generate its certificate. You'll also need Apple's WWDR intermediate certificate.

2. Build the Pass Bundle

A pass is a folder containing:

  • pass.json — the pass's data: style (boardingPass, coupon, eventTicket, storeCard, or generic), your Pass Type ID, a serialNumber + authenticationToken (needed if you'll later use getPasses/checkPassExists/removePass), and the fields shown on the pass (header/primary/secondary/auxiliary/back fields).

  • Images — icon.png, logo.png, and style-specific assets (@2x/@3x variants).

3. Generate & Sign the Manifest

manifest.json lists a SHA hash of every file in the bundle. Sign that manifest with your Pass Type ID certificate + the WWDR certificate to produce a detached signature file:

4. Package as .pkpass

Zip pass.json, manifest.json, signature, and the images together (flat, no subfolder) with a .pkpass extension.

Hand-rolling steps 2–4 for every pass is tedious — most teams use a maintained pass-generation library that wraps this pipeline. For Node.js, passkit-generator is a commonly used one:

There isn't a single dominant equivalent library across every backend language — for PHP or others, the OpenSSL-based signing steps above are the language-agnostic fallback (shell out to openssl, or call it via an extension).

5. Host or Base64-Encode It

Once you have the .pkpass bytes:

  • Host it at an HTTPS URL (serve with Content-Type: application/vnd.apple.pkpass), or

  • Base64-encode it and send the string directly.

Handing It to WebToNative


See Also