Wallet Creating Passes - Android
This page covers the part that happens before you ever call Wallet.addPasses — building and signing the pass JWT itself. WebToNative never creates, edits, or signs a pass; it only hands whatever JWT (or save link) you give it to Google Wallet. See Google Wallet / Apple Wallet for the JS API this feeds into.
1. Create a Google Wallet Console 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. Add Testers
New Issuer accounts start in demo mode — passes only work for Gmail accounts you've explicitly added as testers. Add every account you'll use for testing under the Console's tester list.
Once you've finished testing, move your Issuer account from demo mode to production in the Console — passes won't work for real users until you do.
3. Create a Pass Class
A class is the reusable template for a pass type — the loyalty program, the event, the offer. Create it in the Google Wallet Console, picking the type that matches what you're issuing (Generic, Loyalty, Offer, Event Ticket, Gift Card, Flight, Transit).
Once the class exists, you also need a pass object — one instance of that class holding one user's actual data (their points balance, their seat, their gift card value). You can draft the object's JSON by hand against the Google Wallet objects reference, or use an AI assistant to generate a sample object matching your class's schema as a starting point.
4. Get Your Service Account Key
In Google Cloud Console, enable the Google Wallet API for your project, create a service account, and download its JSON key. This key's private key is what signs the JWT in the next step — keep it off the client and out of version control.
5. Generate the Save JWT
The pass object isn't handed to Wallet.addPasses directly — it's wrapped in a signed JWT. Build the claims below, then sign them:
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.
For quick testing, sign it at jwt.io: select algorithm RS256, paste the claims JSON above into the payload editor, and paste your service account's private key into the signature panel. jwt.io's encoder runs entirely in your browser — it never sends the key anywhere — but it's still meant for testing, not a production pipeline.
When you register the pass object, also register your app's package name and SHA-1 signing key in the Google Wallet Console. A pass will fail to save if the app requesting it isn't registered against your Issuer account.
For a production backend, sign the same claims programmatically instead of pasting the key into a browser tool each time:
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.
See Also
Google Wallet / Apple Wallet — the
Wallet.*JavaScript API this feeds into.Apple Wallet (iOS) — the iOS side of pass creation.
Last updated