Skip to main content

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.
A first issue answers 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
Every accepted update also appends a 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.voided property 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
404 — unknown pass. An id outside the wps_ + 32-hex format, or a pass never issued in this tenant:
404
409 — lifecycle conflict. Update or void a pass that is already voided; issue a replacement pass instead:
409