It's the Thursday before launch. Priya has been testing the Google Wallet integration for three weeks, and every save link has worked on her Pixel. She sends one to the product manager, who taps it on her own phone. The pass fails to save. Priya sends another to a colleague in sales. Same result. Then she asks a friend to try it, and the friend's phone says the pass can't be added at all.
Nothing is wrong with her code. Her Google Wallet issuer account is still in demo mode, and demo mode has one rule that matters more than all the others: only people on a short list can receive your passes.
This post covers the gap between "works for me" and "works for everyone". It starts where the JWT flow ends, with an issuer account that exists and a service account that signs. What follows is what demo mode actually restricts, how to add testers, what the label means, and how to get through the publishing request without losing a launch week.
What demo mode actually is
A new Google Wallet issuer account starts in demo mode. Google's documentation describes it as a way to build and test right after signing up. You get the same API and the same features as a production account. The restriction is on the receiving end.
In demo mode you can only issue passes to Google Wallet users who hold the Admin or Developer role on the issuer account, or who were added as test accounts in the console. Anyone else can't add your passes to their wallet.
That's the whole mechanism. Everything else you do in demo mode is real. You can create pass classes and objects. You can grant a service account REST API access. You can fill in your business profile. You can request publishing access. Google introduced demo mode in a February 2023 developer blog post, and the model hasn't changed in a way that matters to your code.
One limit is easy to miss. Demo accounts can't create additional accounts through issuer.insert. If your platform provisions issuer accounts on behalf of customers, plan for that to wait until publishing access is granted.
The practical consequence is that demo mode proves your signing, your class design and your save flow. It can't prove the one thing a launch depends on, which is that a stranger can tap your link and get a pass.
Why your pass says "[TEST ONLY]"
Passes issued in demo mode show a "[TEST ONLY]" label at the top. Google's docs say it stays until your issuer account is approved for publishing mode, and then it goes away.
You can't remove it with a field. You can't hide it with a theme or a hex color. It isn't part of your pass definition at all. It's a property of the account that issued the pass, and the only fix is the approval.
That has two consequences worth planning around.
Screenshots of demo passes are not marketing assets. If your design team captures the pass for the launch page while the label is showing, they'll ship a picture of a test. Wait for approval, or crop deliberately and tell everyone why.
A label that disappears is a good sign, not a bug. Google says the label goes away once you're approved, and it follows the issuer account. Don't build your own "is this a test pass" check around it. You can't read it from your side anyway.
The wording on Google's pages varies a little. One note in the docs spells the prefix "TEST - Only", while the main text uses "[TEST ONLY]". Treat it as the same thing. If you're searching your own logs or support tickets for it, search both.
Add your testers before you need them
Test accounts are the bridge between a team of one and a team of ten. The setup is short.
- Open the Google Pay and Wallet Console and select Google Wallet API.
- On the Manage tab, choose Set up test accounts.
- Enter each tester's Google Account email on its own line.
- Select Update testers.
Two details save you time. First, the email has to be the Google Account the person uses on the phone where they'll save the pass. A work address that isn't the signed-in account on their device gets you the same failure Priya saw, with no helpful error. Second, testers don't need any access to the issuer account itself. Test accounts exist so you can hand someone a pass without handing them the console.
Admins and developers on the issuer account are test users by default, which is why the pass worked on Priya's Pixel from day one. That default is also why a solo developer can ship a "finished" integration without ever noticing the restriction.
A reasonable test list for a launch is small and deliberate. Include one person on a recent Android phone, one on an older version, one who has never seen the feature, and one from support who will field the questions afterward. Four testers who hit different edges beat forty who all use the same device.
Get a class approved before you issue
Passes live inside classes, and classes carry a review state. The REST API exposes it as reviewStatus, with values such as DRAFT, UNDER_REVIEW, APPROVED and REJECTED. A class has to reach APPROVED before objects built on it can be issued to users in production.
You set the status when you create or update the class. Moving a draft class into review is a single patch:
PATCH https://walletobjects.googleapis.com/walletobjects/v1/genericClass/ISSUER_ID.loyalty_tier_gold
Authorization: Bearer ACCESS_TOKEN
Content-Type: application/json
{
"reviewStatus": "UNDER_REVIEW"
}Google's 2023 write-up notes that classes already in APPROVED state can issue passes once your account moves to publishing mode. So the order matters. Get your classes into review early, and don't leave them in DRAFT until the week you want to launch.
This is also the right moment to freeze your class design. Google's docs treat class edits as reviewable changes, so assume a significant edit after approval may send the class back through review. The colors, the logo and the field layout you test with should be the ones you intend to ship. Object data is different. Names, balances and barcodes change per user and don't need approval. If you've followed the split between class and object in the JWT post, the thing to settle is the class, because that's where the approved branding lives.
The publishing access request, step by step
When the account is ready, the request itself is short. Per Google's documentation:
- Complete your Business Profile in the Google Pay and Wallet Console. This covers business information and a payments profile.
- Open Google Wallet API in the console.
- Once the prerequisites are met, click Request publishing access in the "Get publishing access" box.
The prerequisite that trips people up is the Business Profile. Google uses it to confirm that the issuer account belongs to a real business, organization or individual. A half-finished profile, a mismatched legal name or a payments profile nobody on your team can open will stall the request. Have the person who owns the company's finance setup sit next to you while you fill it in.
The requirements have shifted over time, and that's worth knowing before you trust any old tutorial. In 2023, Google's blog described a step where a Google contact asked for screenshots of your passes, to check them against brand guidelines and the acceptable use policy. The current documentation says screenshots are no longer required for the request. Some tutorials still tell you to prepare them. Preparing them costs you nothing, but don't delay the request waiting for polished ones.
How long approval takes, and what to do while you wait
In 2023, Google said the review could take up to two business days. The current documentation names no timeframe. It says only that the Google Wallet team reviews your issuer account and notifies you when the request is approved.
So plan for two things at once. Don't assume the two-day figure still holds, and don't assume it's slow either. Submit early enough that a slower answer still fits your schedule, and treat the launch date as a function of the approval, not the other way around.
Here is a pattern that shows what goes wrong. Consider a representative mid size retail team, based on an anonymized example. They build the full Google Wallet flow in a sprint, test it on the whole engineering team's phones, and schedule the launch for the following Tuesday. They submit the publishing request on the Friday before. The request comes back asking for a change to their business profile. They fix it Monday, resubmit, and wait. Launch slips by days. Not because the integration was late, but because the request was filed last.
The fix is cheap. File the request as soon as you have one class in review and a complete profile. You can keep building while it's open. Demo mode and publishing mode run the same API, so nothing you write during the wait gets thrown away.
While you wait, use the time on work that needs no approval:
- Test the save flow on a clean device with a fresh Google Account.
- Check what happens when a user taps your link twice, or taps it after deleting the pass.
- Write the support answer for "why can't I add this pass", since that is the question you'll get the day you launch.
- Read how your pass renders on different screen sizes. The rendering differences between the two wallets are bigger than most teams expect.
What changes the day you're approved
Google's docs say that once you receive publishing access, the "[TEST ONLY]" label is removed and you can issue passes to any Google Wallet user. You'll get an email when it happens.
Three things are worth checking that day.
Re-test with someone outside the tester list. This is the real test of the thing you built. Use a personal account that was never added to the console. If the pass saves cleanly with no label, you're done.
Check your classes. Confirm every class you plan to use is in APPROVED. A class still in UNDER_REVIEW or DRAFT is a likely reason an approved account still can't issue a particular pass.
Check your origins. If your save link is triggered from a web page, the origins claim in the JWT must list the exact domain that page runs on. A launch domain that differs from your staging domain breaks the button without any change to your account status. It's an easy launch-day surprise to miss.
Then write down the date, so you know how long the review took the next time you add a class.
Both wallets, one launch plan
Apple has no equivalent of demo mode. Once you've registered a Pass Type ID and generated a certificate, you can issue to any iPhone the same day. That's convenient, and it's also why teams that build Apple first assume Google behaves the same way. It doesn't. Google's approval sits between your finished code and your first real customer, and nothing on your side can speed it up.
The sensible plan treats the two timelines separately. Start the Google Business Profile and publishing request in week one, long before the integration is finished. Build and sign Apple passes in parallel. If you want both wallets from a single definition, the single pass model is built for that split, and it means the approval wait doesn't hold up the Apple side of the launch.
Passmint handles the Google issuer wiring and the class and object split, so the only thing left on your plate is the one step no software can do for you, which is asking Google for access. If you're about to start, create an account at Passmint and file the request first.
Primary sources
Common questions
Technical content writer, Passmint
Julio is a technical content writer at Passmint. He writes about Apple PassKit, the Google Wallet API, and what breaks when wallet passes meet production traffic.
More from Julio Song →![Google Wallet Demo Mode to Production: Fixing the "[TEST ONLY]" Label and Requesting Publishing Access](/blog/google-wallet-demo-mode-to-publishing-access/cover.webp)