Live pass updates
PUT a pass by its serial and it refreshes on every device it is installed on, Apple and Google.
Create a pass with one request, update every installed device with the next. No certificates. JSON in, Apple and Google passes out.
Free up to 1,000 passes/month, then $0.00039 per pass on Pro.
The best alternative to PassKit, Pass2U,
or building on Apple's and Google's SDKs.
Every pass gets a serial number. Call it again to update the pass or send a notification to the customer's lock screen.
One POST with the pass content. Back comes the signed .pkpass, a Save to Google Wallet link, and the serial.
curl -X POST https://api.walletwallet.dev/api/passes \
-H "Authorization: Bearer ww_live_<key>" \
-H "Content-Type: application/json" \
-d '{
"barcodeValue": "LOYALTY-98765",
"barcodeFormat": "QR",
"logoText": "Bayroast Coffee",
"headerFields": [{ "label": "POINTS", "value": "1,250" }],
"primaryFields": [{ "label": "CARD", "value": "Coffee Rewards" }]
}' PUT the updated body to that serial. The pass refreshes on every device it's installed on, and a notification fires.
curl -X PUT https://api.walletwallet.dev/api/passes/<serial> \
-H "Authorization: Bearer ww_live_<key>" \
-H "Content-Type: application/json" \
-d '{
"barcodeValue": "LOYALTY-98765",
"barcodeFormat": "QR",
"logoText": "Bayroast Coffee",
"primaryFields": [{ "label": "CARD", "value": "Coffee Rewards" }],
"headerFields": [{ "label": "POINTS", "value": "1,300", "changeMessage": "You hit %@ points. Free coffee unlocked!" }]
}' Attach coordinates to the serial. When the customer is near the place you set, Apple pins the pass to the lock screen and Google surfaces it in the notification drawer.
curl -X PUT https://api.walletwallet.dev/api/passes/<serial> \
-H "Authorization: Bearer ww_live_<key>" \
-H "Content-Type: application/json" \
-d '{
"barcodeValue": "LOYALTY-98765",
"barcodeFormat": "QR",
"logoText": "Bayroast Coffee",
"primaryFields": [{ "label": "CARD", "value": "Coffee Rewards" }],
"locations": [{ "latitude": 40.7484, "longitude": -73.9857, "relevantText": "Free refill at our Empire State store" }]
}' Every pass gets its own branded page. Send the link anywhere, it opens the right wallet for whoever taps it, and it stays the same through every update.
PUT a pass by its serial and it refreshes on every device it is installed on, Apple and Google.
Every update pushes automatically on both wallets, with no keys to manage.
Each pass gets a hosted page with Add to Apple and Google Wallet buttons. Hand over one link.
Logo, strip banner, colors, and custom field labels.
Up to 10 GPS coordinates per pass; Wallet surfaces it when the user is nearby.
Cloudflare Workers. Sub-200ms pass generation worldwide.
Tune every field, color, and image and watch the pass update. Copy the code when you're done.
Text next to the logo (top-left)
Notification title on pass updates. Defaults to your account name.
No header fields
No primary fields
Apple and Google show only the first primary field; the rest are saved but will not appear on the pass.
No secondary fields
No back fields
Click the pin to fill a row with where you are, for testing. The real pass needs the actual place.
Wallet shows the pass on the lock screen within ~100m of a coordinate.
Pro feature — upgrade to add up to 10 lock-screen location triggers per pass.
Overrides color preset
On Google, your strip image shows beneath the QR code, and header fields sit in the field row, not the top-right corner.
This image is smaller than the recommended size and may look soft on the pass.
Find any pass you have issued, then edit it or send a notification to every device it is installed on. Included with Pro.
Search by name, ticket, email, or serial, see where each pass is installed, then share, edit, push, or revoke it across both wallets, and export the list to CSV.
Bearer auth, JSON in, signed .pkpass out. Click any endpoint to expand the schema.
Authorization: Bearer ww_live_<your_key> Base https://api.walletwallet.dev /api/passes Create a pass for both wallets. Returns JSON with the .pkpass and Google link. | Field | Type | Req | Description |
|---|---|---|---|
| barcodeValue | string | Yes | Data encoded in the barcode (e.g., member ID, ticket number). |
| barcodeFormat | string | Yes | One of QR PDF417 Aztec Code128. |
| logoText | string | No | Text next to the logo (top-left of pass). |
| description | string | No | Accessibility text (not visible). Defaults to logoText. |
| organizationName | string | No | Issuer name shown as the notification title on pass updates and in the Wallet info screen. Max 64 chars. Falls back to your account default. |
| primaryFields | array | No | Main content. Array of {label, value, changeMessage?}. changeMessage is the lock-screen banner template that fires when this field changes during a PUT. |
| secondaryFields | array | No | Fields below primary. Array of {label, value, changeMessage?}. |
| headerFields | array | No | Top-right header area. Array of {label, value, changeMessage?}. |
| backFields | array | No | Back of pass. Array of {label, value, changeMessage?}. |
| locations | array | No | Up to 10 geofences. {latitude, longitude, altitude?, relevantText?} per entry. Surfaces the pass on the lock screen when the device is nearby. |
| sharingProhibited | boolean | No | Hides the Apple Wallet share button. Defaults to true (best for loyalty and membership cards). Set false to let holders share the pass. |
| colorPreset | string | No | Color theme: dark blue green red purple orange. |
| color | string | No | Custom hex color (Pro). e.g., #1e40af. |
| logoURL | string | No | Custom logo image (Pro). HTTPS URL or PNG data URI. |
| thumbnailURL | string | No | Top-right image (Pro). HTTPS URL or PNG data URI. |
| stripURL | string | No | Banner behind the primary field (Pro). Switches to store-card layout. HTTPS URL or PNG data URI. |
| iconURL | string | No | Replaces the default lock-screen notification icon (Pro). Distinct from logoURL. HTTPS URL or PNG data URI. |
| title | string | No | Legacy. Sets primaryFields[0].value + logoText if unset. |
| cardLabel | string | No | Legacy. Sets primaryFields[0].label. Defaults to CARD. |
| label | string | No | Legacy. Sets secondaryFields[0].label. |
| value | string | No | Legacy. Sets secondaryFields[0].value. |
| expirationDays | number | No | Pass expires after this many days. Any integer between 1 and 3650. |
200 JSON: { serialNumber, googleSaveUrl, applePass, shareUrl }. applePass is the base64 .pkpass; googleSaveUrl is the Add to Google Wallet link; shareUrl is a hosted install page you can send straight to users. 400 Invalid request body or missing required fields. 401 Invalid or missing API key. 429 Rate limit exceeded. 500 Server error. curl -X POST https://api.walletwallet.dev/api/passes \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ww_live_<your_key>" \
-d '{
"barcodeValue": "MEMBER-12345",
"barcodeFormat": "QR",
"logoText": "Bayroast Coffee",
"primaryFields": [{"label": "CARD", "value": "Coffee Rewards"}],
"colorPreset": "green"
}' /api/passes/<serial> Push new field values. Every installed device refreshes within seconds, on both wallets. Same shape as POST: send the full pass body. The new body replaces the stored pass, so include every field you want to keep — omitted fields are dropped, not merged. Identical bodies are no-ops: no APNs push, no quota cost. Setting changeMessage on a field whose value changed sets the lock-screen banner text.
200 JSON: { serialNumber, lastUpdated, notifiedDevices, unchanged }. A changed body re-signs the pass and pushes to every installed device; an identical body returns unchanged: true with no push and no quota cost. 400 Invalid request body. 401 Invalid or missing API key. 404 Serial not found. 429 Rate limit exceeded. curl -X PUT https://api.walletwallet.dev/api/passes/<serial> \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ww_live_<your_key>" \
-d '{
"headerFields": [{
"label": "POINTS",
"value": "1,300",
"changeMessage": "Now at %@ points"
}]
}' /api/passes/<serial> Revoke a pass. Invalidates it on every device it is installed on, both wallets. Revoke a pass the moment you need to: a single DELETE invalidates it everywhere it is installed across both wallets, with no request body to send. How revoke works on each wallet.
200 JSON: { serialNumber, deleted, googleRevoked, notifiedDevices, lastUpdated }. Marks the pass void and expired on every device it is installed on, both wallets. A repeat call returns alreadyDeleted: true. 401 Invalid or missing API key. 404 Unknown serial, or a serial owned by a different key. 429 Rate limit exceeded. curl -X DELETE https://api.walletwallet.dev/api/passes/<serial> \
-H "Authorization: Bearer ww_live_<your_key>" Coding with Codex, Claude, or another agent? Point it at /llms.txt for tight, up-to-date docs.
For reference, PassKit charges $1,300/month for the same pass lifecycle features.
Build and test
Ship to production
Past 100,000/month? Overage is $0.00039 per pass. Get in touch.
Start 30-day trialScale on your own cert
Includes setup support for provisioning your Apple and Google credentials.
Schedule a callYour monthly total counts each pass you create and each update that changes a pass. One pass covers both Apple and Google and counts once, so you are never billed per platform.
I built WalletWallet because I needed Wallet passes for one of my apps, and the options were a clunky dashboard or a week waiting on Apple for a signing certificate. Now it's one API call, signed with our cert, no Apple account needed. Send me an email, I read them all.
Build a white-label notification CRM on our API. Your agency clients pay you per customer they reach. We charge you $39 flat, no matter how many customers move through it.
Hand every attendee a pass that lives next to their physical badge. Push session changes, room swaps, and tomorrow’s agenda straight to their lock screen.
Drop a pass into every order confirmation. Ping customers on the lock screen for restocks, drops, and order updates. No app install.
Your clients are businesses with their own customers to reach. Integrate WalletWallet once and the Wallet pass feature ships across every account on your platform. We don’t bill per client.
Every new account starts on Pro for 30 days: all features, all image slots, lifecycle updates, and 100,000 passes a month. After that, keep Pro at the $39/month standard rate or stay free under 1,000 passes/month. No card up front, no auto-charge.
Yes, fully. One API call lands a pass in both wallets: Apple installs the signed .pkpass, and Google installs from a Save to Google Wallet link we generate for the same pass. Live updates and push work on both too. We re-sign and push to Apple over APNs, and update the Google object and push directly. One honest difference: Apple shows your custom message on the lock screen, while Google's update banner is generic and your text lives inside the pass.
No. One pass generation covers both platforms. A single POST /api/passes returns the signed Apple .pkpass and a Save to Google Wallet link for the same pass, and it counts as one pass against your plan, not one per wallet. Updates and push to both wallets are included in that same pass, so there are no per-platform fees.
Two things count: each pass you create with POST /api/passes, and each update that changes a pass with PUT /api/passes/<serial>. A card you issue once and refresh a few times over its life is the create plus each content change, not a new pass every month. Revoking a pass does not count.
Yes. Every pass gets a unique serial, returned as serialNumber in the JSON response and embedded inside the .pkpass file. PUT a new body to /api/passes/<serial> and the pass refreshes on every device it was added to, iPhone, iPad, Apple Watch, and Android. Identical bodies don't trigger a push and don't count against your quota.
The API response carries the signed .pkpass (base64 applePass) and a Save to Google Wallet link for the same pass. Forward them however you already reach your user: email, an "Add to Wallet" button on a confirmation page, SMS, or in-app. Or share the hosted pass page we host at /p/<serial>, which shows the right Add button for the visitor's phone, Apple on iPhone, Google on Android.
Free under 1,000 passes a month. $39 flat above that, with 30 days of Pro on every new account.
curl -X POST https://api.walletwallet.dev/api/passes …