Guides
Updating and notifying
Change a pass on holders' phones, tell them about it, and retire it.
A pass isn't a file you send once. When its content changes, send the new content: installed passes refresh on holders' phones, on Apple Wallet and Google Wallet alike.
Update a pass
Send the whole pass again to Update a pass, as it should now be. A field you leave out is removed.
curl -X PUT "https://api.walletpassapi.com/v1/passes/9f904677-e06d-4b0f-8404-878ff1066f88" \
-H "Authorization: Bearer $WALLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"organizationName": "Acme Coffee",
"logoText": "Acme",
"primaryFields": [
{
"key": "points",
"label": "Points",
"value": "135",
"changeMessage": "You now have %@ points"
}
],
"barcodeValue": "MEMBER-1042",
"barcodeFormat": "QR"
}'const res = await fetch("https://api.walletpassapi.com/v1/passes/9f904677-e06d-4b0f-8404-878ff1066f88", {
method: "PUT",
headers: {
Authorization: `Bearer ${process.env.WALLET_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"organizationName": "Acme Coffee",
"logoText": "Acme",
"primaryFields": [
{
"key": "points",
"label": "Points",
"value": "135",
"changeMessage": "You now have %@ points"
}
],
"barcodeValue": "MEMBER-1042",
"barcodeFormat": "QR"
}),
});
const data = await res.json();import os
import requests
res = requests.put(
"https://api.walletpassapi.com/v1/passes/9f904677-e06d-4b0f-8404-878ff1066f88",
headers={"Authorization": f"Bearer {os.environ['WALLET_API_KEY']}"},
json={
"organizationName": "Acme Coffee",
"logoText": "Acme",
"primaryFields": [
{
"key": "points",
"label": "Points",
"value": "135",
"changeMessage": "You now have %@ points",
},
],
"barcodeValue": "MEMBER-1042",
"barcodeFormat": "QR",
},
)
data = res.json()<?php
$ch = curl_init("https://api.walletpassapi.com/v1/passes/9f904677-e06d-4b0f-8404-878ff1066f88");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "PUT",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("WALLET_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"organizationName" => "Acme Coffee",
"logoText" => "Acme",
"primaryFields" => [
[
"key" => "points",
"label" => "Points",
"value" => "135",
"changeMessage" => "You now have %@ points",
],
],
"barcodeValue" => "MEMBER-1042",
"barcodeFormat" => "QR",
]),
CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);To change one field without keeping a copy of the pass, get its fields, change the one, and send them all back.
Only what changed costs anything
An update that changes nothing (the same content again) makes no new version, sends nothing to phones and uses no operation. So it's safe to send an update on every change in your system, without checking first whether the pass is affected.
A real change makes a new version, uses one operation, and is pushed to the pass's Apple devices and patched on Google Wallet. The answer's platforms says what happened on each:
- Apple:
queued,no_devices(not installed on an iPhone yet) orno_push_key(your issuer has no Apple push key, so phones can't be told). - Google:
queued, ornot_savedwhen no one has saved it yet.
Get a pass shows how the latest one was delivered, in delivery.lastUpdate: sending, retrying, delivered or failed.
Show a notification
There are two ways to put something on holders' lock screens.
When a value changes. Give the field a changeMessage, with %@ where the new value goes. When an update changes that field's value, Wallet shows "You now have 135 points". A field without one changes quietly.
A message of your own. Send a notification with a message:
curl "https://api.walletpassapi.com/v1/passes/9f904677-e06d-4b0f-8404-878ff1066f88/notifications" \
-H "Authorization: Bearer $WALLET_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"message": "Double points this weekend"
}'const res = await fetch("https://api.walletpassapi.com/v1/passes/9f904677-e06d-4b0f-8404-878ff1066f88/notifications", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.WALLET_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
"message": "Double points this weekend"
}),
});
const data = await res.json();import os
import requests
res = requests.post(
"https://api.walletpassapi.com/v1/passes/9f904677-e06d-4b0f-8404-878ff1066f88/notifications",
headers={"Authorization": f"Bearer {os.environ['WALLET_API_KEY']}"},
json={
"message": "Double points this weekend",
},
)
data = res.json()<?php
$ch = curl_init("https://api.walletpassapi.com/v1/passes/9f904677-e06d-4b0f-8404-878ff1066f88/notifications");
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer " . getenv("WALLET_API_KEY"),
"Content-Type: application/json",
],
CURLOPT_POSTFIELDS => json_encode([
"message" => "Double points this weekend",
]),
CURLOPT_RETURNTRANSFER => true,
]);
$data = json_decode(curl_exec($ch), true);The message is kept in the pass's Latest message field, on its back, so a holder who missed the banner can still read it. A pass's first message adds that field, and Apple may not show a banner for it; later ones show.
To send one message to many passes, such as every gold member, send a broadcast with the same search and filters as List passes. Preview it first to see how many it reaches and what it costs.
Passes with placeholders
A pass made from a template, or with {{placeholders}} of its own, keeps its design and its values separately. To change its values, send only those:
{ "data": { "points": 135 } }They're merged over its values ("" clears one), and its design is filled again. holder works the same way. A pass made from a template keeps that template's design: sending fields to it is refused with template_linked, unless you add "unlinkTemplate": true to give it a design of its own.
Retire a pass
Revoke it. Holders' copies are voided at once: it can't be scanned, updated or installed again, and there's no undo, because phones keep a voided pass voided. To issue it again, create a new one.
A revoked pass is deleted 30 days later, keeping only its serial number. To delete it sooner, use Delete a revoked pass, from 24 hours after the revoke, so phones have time to receive the voided copy.
Each of these is also a webhook event: pass.updated, pass.revoked and pass.erased.