WalletWallet API
New iOS 27: tappable actions and poster background images

The easiest Wallet pass API.

Create a pass with one request, update every installed device with the next. JSON in, Apple and Google passes out.

Apple Wallet Google Wallet

Free up to 1,000 passes/month, then $39 a month on Pro.

The best alternative to PassKit, Pass2U,
or building on Apple's and Google's SDKs.

Shotokan Karate
BELT
1st Dan
MEMBER
Adult Program
EXPIRES
Jun 2027
Metropolitan Museum
Guest No.
102035
Member Name
Ryan Notch
Expires
01/02/27
Iron Peak Gym
Unlimited
MEMBERSHIP
VISITS
214
RENEWS
Monthly
Eastside Public Library
MEMBER
Reading Pass
EXPIRES
Mar 2026
Bayroast Coffee
Points
1,250
Member
Alen Todorov
Tier
Gold Status
Iron Peak Gym
VISITS
214
MEMBERSHIP
Unlimited
RENEWS
Monthly
Metropolitan Museum
Patron
MEMBERSHIP
GALLERIES
All
SINCE
2021
Alpine Ridge
Days
12
Lift Pass
Season
Valid
'26–'27
Neon Nights Live
SEAT
GA
EVENT
Sat · 9:00 PM
GATE
B
Bayroast Coffee
Coffee Rewards
CARD
POINTS
1,250
TIER
Gold Status
Stillwater Yoga
CLASSES
8
MEMBERSHIP
Unlimited
EXPIRES
Apr 2026
Riverside University
STUDENT
Ava Chen
CLASS OF
2027
Cellar 33 Wine Club
TIER
Reserve
MEMBERSHIP
Quarterly
BOTTLES
24 / yr
Alpine Ridge Resort
Season
LIFT PASS
DAYS
12
VALID
'26–'27

Shops, schools, clubs, studios, and events run on it.

One API, one platform: loyalty cards, member cards, and tickets, updated on every phone they are installed on.

Paper & Tea Retail
Bialik Schools
Apranga Retail
Welkoop Retail
Brebeuf Jesuit Schools
Blickfang Events
Merkalia Agencies
Referral Booster Loyalty
Precision Golf Clubs
Société Nautique de Nyon Clubs
Kidz Mall Retail
Oslo Fotokunstskole Schools
Ambiscale Agencies
Agência Koko Agencies
Augusta County Library Libraries
Fajile Loyalty
passes issued
100,000+ passes issued
devices carrying a pass
33,000+ devices carrying a pass
businesses
2,400+ businesses

See how we handle security and customer data

Issue passes once, update them anytime.

Every pass gets a serial number. Call it again to update the pass or send a notification to the customer's lock screen.

  1. Issue the pass

    Build it in the dashboard, ask your AI assistant, or send one API request. 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 <your_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" },
          { "label": "TIER", "value": "Gold Status" }
        ],
        "backgroundURL": "https://bayroast.example/poster.png",
        "featuredActions": [
          { "identifier": "order", "type": "order", "url": "https://bayroast.example/order" },
          { "identifier": "rewards", "type": "viewOffersRewards", "url": "https://bayroast.example/rewards" }
        ]
      }'

    Poster and featured actions: iOS 27+.

  2. Push updates

    Change anything on the pass and it refreshes on every device it is installed on, with a notification on the lock screen.

    curl -X PUT https://api.walletwallet.dev/api/passes/<serial> \
      -H "Authorization: Bearer <your_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!" }]
      }'
  3. Surface it by location

    Attach a place to the pass. When the customer is nearby, Apple pins it 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 <your_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" }]
      }'

Share a pass with one link.

Every pass gets its own branded page, translated into the visitor's language. Send the link anywhere, it opens the right wallet for whoever taps it, and it stays the same through every update.

Make the page yours.

On the Business plan the page runs on your own domain, in your colors, with your logo and your wording.

Why WalletWallet?

Live pass updates

PUT a pass by its serial and it refreshes on every device it is installed on, Apple and Google.

Push notifications

Every update pushes automatically on both wallets, with no keys to manage.

A shareable page per pass

Each pass gets a hosted page with Add to Apple and Google Wallet buttons. Hand over one link.

Your branding

Logo, strip banner, colors, and custom field labels.

Lock-screen locations

Up to 10 GPS coordinates per pass; Wallet surfaces it when the user is nearby.

Edge-deployed

Cloudflare Workers. Sub-200ms pass generation worldwide.

Preview the pass before you issue it.

Tune every field, color, and image and watch the pass update. Create it in the dashboard and share the link, or copy the request into your code.

Editing pass loading...
View all passes

Text next to the logo (top-left)

Notification title on pass updates. Defaults to your account name.

No header fields

The poster layout shows the first header field only.

No primary fields

Without a background image Apple shows only the first primary field on the pass face; Google shows the first as the title and lists the rest in the pass details.

The poster layout shows up to four primary fields on the pass face; Google shows the first as the title and lists the rest in the pass details.

No secondary fields

The poster layout keeps secondary fields off the pass face on iOS 27; older devices and Google still show them.

Up to two short lines along the bottom of the poster layout.

Apple shows the value only; the label is saved but not drawn.

Without a background image Apple keeps them off the pass face; Google still lists them in the pass details.

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.

Up to two buttons under the pass. Apple sets the icon and wording; Google Wallet shows them as links.

Pro feature. Upgrade to add up to two buttons under the pass.

Line breaks are kept, so a multi-line value such as a vCard scans as one. Up to 1024 characters.

By default Google prints the value under the code and Apple prints nothing.

Overrides color preset

EXPIRES

Google Wallet fills the screen with the pass: your background image becomes a full-width band under the fields, and featured actions become tappable rows.

Edit a pass that's already on a phone. No code.

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.

Create passes from ChatGPT, Claude, or Zapier.

Connect the assistant you already use and run your program from it, from issuing cards to editing passes already on phones. Zapier runs the same steps when a sale or signup happens in another app.

ChatGPT JD

Create a loyalty card for Bayroast Coffee. Dark black, a stamp counter out of 10, member name Nora Hale, member number 30427. Give me the share link.

Used WalletWallet

Done. The Bayroast Coffee card is live for both Apple Wallet and Google Wallet.

Bayroast Coffee, Nora Hale

Stamps 0 / 10, member no. 30427, QR of the member number

Open share link

Send Nora that link and the card installs on either phone. Tell me when she earns a stamp and I will update it.

Ask anything

Turn a CSV into a batch of passes. One upload.

Export your members from any CRM, upload the CSV, and design one pass template. Every row becomes a pass with its own share link.

One row per pass. Columns become {{tokens}} in the pass template, and the finished batch exports a CSV of serials and share links.

The full API. Three endpoints.

Bearer auth, JSON in, signed .pkpass out. Click any endpoint to expand the schema.

Auth Authorization: Bearer <your_key> Base https://api.walletwallet.dev
POST /api/passes

Request body

Field Type Req Description
barcodeValue string No Optional. Data encoded in the barcode (e.g., member ID, ticket number). Max 1024 characters. Omit it for a pass with no barcode.
barcodeFormat string No Required only when you send a barcodeValue, in which case it must be one of QR PDF417 Aztec Code128. Note: Code128 is a 1D barcode whose width grows with every character — keep its value under ~80 characters, or it renders too wide to scan reliably. The 2D formats (QR, Aztec, PDF417) handle the full 1024 characters.
barcodeAltText string No Text under the barcode. Max 128 characters. Omit it to keep each wallet's default, which is nothing on Apple Wallet and the barcode value on Google Wallet. Send an empty string to show nothing on both.
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?}. Omit label (or send an empty string) to render the value alone, with no label, on both wallets. 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?}.
footerFields array No Up to 2 fields along the bottom of the poster layout (Pro). Apple draws them on iOS 27+ with backgroundURL; Google lists them in the pass details either way. Array of {label?, value, changeMessage?}; Apple shows the value only.
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.
featuredActions array No Up to 2 tappable tiles under the pass face on iOS 27+ (Pro). {identifier, type, url} per entry, in priority order. Apple picks the icon and label from type; one of Apple's 14 types such as membershipBenefits or place. Google Wallet shows each as a link button.
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. Recommended 160×160 px, max 1MB.
wideLogoURL string No Wide wordmark (Pro), 1280×400 px transparent PNG. Google Wallet shows it top-left and drops logoText and the round logo from the card. Apple Wallet uses it as the logo only when logoURL is absent, and as the lock-screen icon when iconURL is absent too. HTTPS URL or PNG data URI, max 1MB.
thumbnailURL string No Top-right image (Pro). HTTPS URL or PNG data URI. Recommended 180×180 px, max 1MB.
stripURL string No Banner behind the primary field (Pro). Switches to store-card layout. HTTPS URL or PNG data URI. Recommended 1080×360 px, max 1MB.
backgroundURL string No Full-bleed poster artwork (Pro). Apple's poster layout on iOS 27+, classic layout before that; Google shows it beneath the card. HTTPS URL or PNG data URI. 690×1010 px, max 1MB.
iconURL string No Replaces the default lock-screen notification icon (Pro). Distinct from logoURL. HTTPS URL or PNG data URI. Recommended 120×120 px, max 1MB.
credentials string No Slug of one of your credential sets (Pro): the pass is signed with your own Apple certificate and issued from your own Google issuer. Omit for the WalletWallet certificates. Fixed at creation.
title string No Legacy. Sets primaryFields[0].value + logoText if unset.
cardLabel string No Legacy. Sets primaryFields[0].label. Defaults to CARD when omitted; an empty string means no label.
label string No Legacy. Sets secondaryFields[0].label.
value string No Legacy. Sets secondaryFields[0].value.
expirationDays number No Pass expires this many days after the request that sets it; an update that sends it restarts the count. Any integer between 1 and 3650. Not allowed together with expirationDate.
expirationDate string No The exact instant the pass expires, as an RFC 3339 date-time with a UTC offset, e.g. 2027-01-31T23:59:00Z. At most 10 years ahead; in the future on create, any date on update. Not allowed together with expirationDays.

Response

  • 200 JSON: { serialNumber, googleSaveUrl, applePass, shareUrl, credentials, expirationDate }. 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; expirationDate is the UTC instant the pass expires, present only when it expires.
  • 400 Invalid request body or missing required fields. Request body max 2MB, built pass max 10MB, each image max 1MB.
  • 401 Invalid or missing API key.
  • 429 Rate limit exceeded.
  • 500 Server error.

Example

curl -X POST https://api.walletwallet.dev/api/passes \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your_key>" \
  -d '{
    "barcodeValue": "MEMBER-12345",
    "barcodeFormat": "QR",
    "logoText": "Bayroast Coffee",
    "primaryFields": [{"label": "CARD", "value": "Coffee Rewards"}],
    "colorPreset": "green"
  }'
Full POST reference →
PUT /api/passes/<serial>

Request body

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.

Response

  • 200 JSON: { serialNumber, lastUpdated, notifiedDevices, unchanged, expirationDate }. 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. Request body max 2MB, built pass max 10MB, each image max 1MB.
  • 401 Invalid or missing API key.
  • 404 Serial not found.
  • 429 Rate limit exceeded.

Example

curl -X PUT https://api.walletwallet.dev/api/passes/<serial> \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer <your_key>" \
  -d '{
    "headerFields": [{
      "label": "POINTS",
      "value": "1,300",
      "changeMessage": "Now at %@ points"
    }]
  }'
Full PUT reference →
DELETE /api/passes/<serial>

Behavior

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.

Response

  • 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.

Example

curl -X DELETE https://api.walletwallet.dev/api/passes/<serial> \
  -H "Authorization: Bearer <your_key>"
Full DELETE reference →

Coding with Codex, Claude, or another agent? Point it at /llms.txt for tight, up-to-date docs.

Easy pricing that doesn't bill per device or per active pass.

Every new account starts with a 7-day trial of every feature, team members included, with 1,000 passes a month. No card needed.

Free

Build and test

$0 /month
  • 1,000 passes/month (creations + updates)
  • Apple & Google Wallet delivery
  • Pass Editor: design passes visually
  • Batch import: turn a CSV into passes (up to 100 per batch)
  • Signed .pkpass downloads
  • Limited branding
Start free
7-day trial

Pro

Ship to production

$39 /month
  • 100,000 passes/month (creations + updates)
  • Live updates on Apple & Google Wallet
  • Pass Editor: design passes visually
  • Pass Manager: edit passes, no code
  • Batch import: turn a CSV into passes (up to 1,000 per batch)
  • Lock-screen location triggers
  • Logo, thumbnail, cover image, icon
  • Send push notifications
  • Sign with your own Apple certificate & Google issuer
Start 7-day trial

Business

Grow with your team

$99 /month
  • 1,000,000 passes/month (creations + updates)
  • Everything in Pro
  • Soft limit: requests keep working past 1,000,000 and we reach out
  • Priority support
  • Multiple team members
  • Share pages on your own domain: passes.yourbrand.com
  • Share pages in your branding: colors, logo, and wording
Start 7-day trial

Scale

High volume with a dedicated team

Starts at $379 /month
Schedule a call
  • Everything in Business
  • Managed APNs on dedicated, low-latency workers
  • Pass Editor: design passes visually
  • Batch import: turn a CSV into passes (up to 1,000 per batch)
  • Starts at 10,000,000 passes per month and scales with your volume
  • Service level agreement & dedicated technical support
  • Pass Manager: edit passes, no code
  • Dedicated onboarding

Looking for something different?

We'll put together a plan that fits your needs.

Get in touch

Creates and updates both count toward your monthly total. One pass covers Apple and Google and counts once.

Evaluating us for procurement? The DPA, sub-processor list, and security overview are in the Trust Center.

Cool things you can build.

  • WalletWallet For agencies

    Run an agency? Sell a lightweight CRM to your small business clients.

    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.

  • WalletWallet For event organizers

    Host events? Make the badge update itself.

    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.

  • ShopifyWoo For store owners

    Running a small store? Skip the app build.

    Drop a pass into every order confirmation. Ping customers on the lock screen for restocks, drops, and order updates. No app install.

  • WalletWallet For B2B SaaS

    Building a B2B SaaS? Ship Wallet passes for every client.

    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.

Building something specific? See how the API shapes loyalty cards, punch cards, membership cards, and event tickets.

Frequently asked questions

What's in the 7-day trial?

Every new account starts with 7 days of every feature on every plan: all image slots, lifecycle updates, Pass Manager, and team members. The trial includes 1,000 passes a month, the same volume as Free. At the end, subscribe to Pro at $39/month or Business at $99/month, or stay free under 1,000 passes/month. We do not ask for a card up front and we do not auto-charge.

Does this work with Google Wallet too?

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.

Do Apple and Google Wallet count as two passes?

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.

What counts toward my monthly passes?

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.

Can I update a pass after it's been added to someone's wallet?

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.

How do I send the pass to my customers?

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.

Issue your first pass in five minutes.

Free under 1,000 passes a month. $39 flat above that, with a 7-day trial on every new account.

curl -X POST https://api.walletwallet.dev/api/passes …