Worked wallet-passes samples
The endpoint list below documents every operation’s parameters; this overlay sequences the round trip a wallet integration actually runs: issue a pass → read its state → push a content update → list and filter. Success envelopes are{ data, meta }, error envelopes are
{ error, meta } — both shapes are covered in How to read a worked
sample. Run the samples with a sandbox
(dv_test_sk_*) key; nothing below needs Apple or Google credentials
until a holder opens the save link.
Every response carries meta.request_id. Quote it when you report a
problem — support can trace the pass end-to-end in the ledger.
1. Issue a pass
POST /api/v1/wallet-passes/issue mints a pass. type is one of
loyalty_card, coupon, or ticket; title is required;
contact_id / external_id are optional correlation links. Brand
fields are organization_name, background_color,
foreground_color, and label_color (#RRGGBB). The barcode payload
is barcode_message plus barcode_format — QR_CODE (default),
PDF_417, AZTEC, or CODE_128. fields takes up to 20
{key, label, value} rows, and expires_at bounds the pass. The same
body with the same idempotency_key replays the original pass instead
of minting a duplicate.
201 (a replay of the same idempotency_key
answers 200 with "replayed": true and the pass’s current
state). platforms carries the per-platform install payloads:
201
platforms.apple.configured / platforms.google.configured tell you
whether your account’s wallet credentials are connected (a platform
that is not reports reason). Apple’s pass_json and Google’s
object + save_url are what a client wraps into the wallet install
flow; platform payloads are rebuilt on every read, so a save link
starts working the moment credentials are connected — no re-issuance.
2. Read the pass back
GET /api/v1/wallet-passes/{id} returns the pass folded to its current
state — freshly issued or updated, status reads active; after a
void it reads voided, with voided_at and void_reason set. Prefer
a re-read over the issue echo when you need the current save link or
the latest state.
3. Push an update
POST /api/v1/wallet-passes/{id}/update is the patch: send only the
content fields you are changing — a points fields re-render, a fresh
subtitle, a coupon expires_at. Each accepted update bumps
generation; the holder’s wallet refreshes from the platform push
channel (Google’s object endpoint, Apple’s push notification), so the
new balance shows without the holder re-saving the pass. An empty
body is rejected at 422 with at least one field must be provided;
updating a voided pass answers 409.
200
wallet_pass.updated event to
your tenant’s event ledger — the webhook your integration receives
back confirming the push, carrying pass_id, only the changed
content fields, and updated_by. Issue and void append
wallet_pass.issued / wallet_pass.voided the same way; subscribe to
them for your own pass-lifecycle automation, and see §6 for where the
shapes live.
4. List and filter passes
GET /api/v1/wallet-passes pages passes newest-first with each row
folded to its current state. Filter with type
(loyalty_card|coupon|ticket), status (active|voided), or
contact_id, and page with limit (max 200) and offset;
meta.pagination.has_more says whether the next page exists.
200
5. Void a pass
POST /api/v1/wallet-passes/{id}/void is terminal: the pass flips to
status: "voided", the wallet expires it at the next refresh, and any
later update or void answers 409 (already_voided). Optional reason
travels with the record as void_reason:
200
6. Where the concepts and events live
- Wallet passes channel — the channel concept: platform accounts, the save-link distribution pattern, and the ledger model behind issuance state.
- Webhook event catalog — the
delivery envelope your webhook endpoint receives; the
wallet_pass.issued/wallet_pass.updated/wallet_pass.voidedproperty shapes are the event payloads above, and the CDP endpoint page tails them live per tenant.
7. Errors worth branching on
Errors follow the{ error, meta } envelope. The three failures every
issuer hits:
422 — field validation. A color outside #RRGGBB, an unknown
type or barcode_format, more than 20 fields, or an empty update
body:
422
wps_ + 32-hex format, or a
pass never issued in this tenant:
404
409