A unique serial per pass
Call it any time after issue to update the pass and push lock-screen notifications. One call reaches every device the customer installed it on: iPhone, iPad, Apple Watch.
Create a pass with one request, update every installed device with the next. No certificates. JSON in, .pkpass out. Apple and Google Wallet.
Push updates are Apple-only for now.
Free up to 1,000 passes/month, then $0.00019 per pass on Pro.
An alternative to PassKit, Pass2U,
or building on Apple's SDK.
Every pass gets a serial number. Call it again to update the pass or send a notification to the customer's lock screen. Communicate with users without making them download an app.
POST the pass content. You get back a .pkpass and its own serial number. The customer adds it to Apple or Google Wallet.
curl -X POST https://api.walletwallet.dev/api/pkpass \
-H "Authorization: Bearer ww_live_<key>" \
-H "Content-Type: application/json" \
-d '{
"logoText": "Bayroast Coffee",
"headerFields": [{ "label": "POINTS", "value": "1,250" }],
"primaryFields": [{ "label": "CARD", "value": "Coffee Rewards" }]
}' \
-o pass.pkpass PUT new fields to that serial. The pass refreshes on every Apple device it's installed on, and your message shows as a lock-screen notification.
curl -X PUT https://api.walletwallet.dev/api/pkpass/<serial> \
-H "Authorization: Bearer ww_live_<key>" \
-d '{
"headerFields": [{
"label": "POINTS",
"value": "1,300",
"changeMessage": "Now at %@ points"
}]
}' Attach coordinates to the serial. Apple pins the pass to the lock screen when the customer is near the place you set.
curl -X PUT https://api.walletwallet.dev/api/pkpass/<serial> \
-H "Authorization: Bearer ww_live_<key>" \
-d '{
"locations": [{
"latitude": 40.7484,
"longitude": -73.9857,
"relevantText": "Free refill at our Empire State store"
}]
}' No certificate to manage or APNs to setup. You only need to store the serial.
Call it any time after issue to update the pass and push lock-screen notifications. One call reaches every device the customer installed it on: iPhone, iPad, Apple Watch.
PUT new fields to a serial. The pass refreshes on every iPhone, iPad, and Apple Watch it installed on.
APNs handled automatically. A lock-screen banner shows the changeMessage you set.
Logo, thumbnail, strip banner, foreground and background colors, custom field labels.
Up to 10 GPS coordinates per pass. Wallet shows the pass when the user is nearby.
Hosted on 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
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
Lock-screen and pass-update notification image. Defaults to your logo.
Wide banner image. Use secondary fields for readable text when using this option.
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/pkpass Create a signed pass. Returns the .pkpass binary. | 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. |
| 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 Returns application/vnd.apple.pkpass binary with an X-Serial-Number header. 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/pkpass \
-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"
}' \
-o pass.pkpass /api/pkpass/<serial> Push new field values. Every installed device refreshes within seconds. Same shape as POST. Send only the fields you want to change — everything else carries over from the existing pass. Identical bodies are no-ops: no APNs push, no quota cost. Setting changeMessage on a field that changed sets the lock-screen banner text.
200 Returns the new .pkpass binary. Triggers an APNs wake to every installed device. 204 Identical body — no push, no quota cost. 401 Invalid or missing API key. 404 Serial not found. 429 Rate limit exceeded. curl -X PUT https://api.walletwallet.dev/api/pkpass/<serial> \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ww_live_<your_key>" \
-d '{
"headerFields": [{
"label": "POINTS",
"value": "1,300",
"changeMessage": "Now at %@ points"
}]
}' 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.
Testing & side projects
Production apps
Sign with your Apple Developer ID
I built WalletWallet because I needed Wallet passes for one of my apps, and the options were a $40/month dashboard or a week waiting on Apple for a signing certificate. Now it's one API call, signed with our cert, $19 flat. My email is on every page. I read all of it.
Alen, founder
Build a white-label notification CRM on our API. Your agency clients pay you per customer they reach. We charge you $19 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, unlimited passes. After that, keep Pro at $19/month or stay free under 1,000 passes/month. No card up front, no auto-charge.
The signed .pkpass file we return opens directly in Google Wallet on Android, so one API call lands a pass in both wallets. Live updates and push notifications are Apple-only. Google Wallet doesn't honor webServiceURL.
Yes. Every pass gets a unique serial, returned in the X-Serial-Number response header and embedded inside the .pkpass file. PUT a new body to /api/pkpass/<serial> and the pass refreshes on every iPhone, iPad, or Apple Watch the customer added it to. Identical bodies don't trigger a push and don't count against your quota.
The API response is the signed .pkpass binary. Forward it however you already reach your user: email attachment, "Add to Wallet" button on a confirmation page, SMS link, or in-app download. Apple Wallet picks it up automatically when opened on iPhone. Google Wallet does the same on Android.
Free under 1,000 passes a month. $19 flat above that, with 30 days of Pro on every new account.
curl -X POST https://api.walletwallet.dev/api/pkpass …