Passes
Passes are individual wallet passes issued to clients. Each pass is based on a pass template and is linked to a client that holds the identity (name, email, phone) and custom_fields rendered onto the pass.
All pass endpoints are dedicated /wallethero-api/... endpoints
Earlier SDK versions hit Directus-native /items/passes. They no longer do. Every method on wh.passes now calls a dedicated, workspace-scoped wallethero-api endpoint guarded by createWorkspaceGuard. The only Directus-native endpoints still used by the pass/template SDK are file upload (POST /files) and asset delivery (GET /assets/:id) — see Template Images.
Auth: Bearer token — caller must be a member of the workspace the pass belongs to. List/create routes derive the workspace from the path; get/update/delete routes load the pass row and check membership against its workspace_id.
List Passes
GET /wallethero-api/workspace/:workspaceId/passes
Lists all passes in a workspace, sorted by newest first. Cross-workspace listing is not supported — the SDK throws if filter.workspace_id._eq is missing.
Auth: Bearer token — workspace member.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
workspaceId | string (UUID) | Workspace identifier |
Example Request
curl "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/passes" \
-H "Authorization: Bearer YOUR_TOKEN"Response (200)
{
"data": [
{
"id": "pass-uuid",
"pass_template_id": "template-uuid",
"project_id": "project-uuid",
"workspace_id": "workspace-uuid",
"client_id": "client-uuid",
"apple_pass_url": "https://api.wallethero.app/...",
"google_pass_url": "https://pay.google.com/gp/v/save/...",
"date_created": "2024-01-15T10:30:00Z"
}
]
}SDK
const passes = await wh.passes.list({
filter: { workspace_id: { _eq: "WORKSPACE_ID" } },
});
// Convenience wrappers (all route through list):
await wh.passes.getByWorkspace("WORKSPACE_ID");
await wh.passes.getByTemplate("TEMPLATE_ID", { filter: { workspace_id: { _eq: "WORKSPACE_ID" } } });
await wh.passes.search("john", { filter: { workspace_id: { _eq: "WORKSPACE_ID" } } });Get Pass
GET /wallethero-api/passes/:id
Fetches a single pass by its UUID.
Auth: Bearer token — member of the pass's workspace.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string (UUID) | Pass identifier |
Example Request
curl "https://api.wallethero.app/wallethero-api/passes/PASS_ID" \
-H "Authorization: Bearer YOUR_TOKEN"Response (200)
{
"data": {
"id": "pass-uuid",
"pass_template_id": "template-uuid",
"project_id": "project-uuid",
"workspace_id": "workspace-uuid",
"client_id": "client-uuid",
"notification": null,
"barcode_value": "1234567890",
"apple_pass_url": "https://api.wallethero.app/...",
"apple_qrcode_url": "https://api.wallethero.app/...",
"google_pass_url": "https://pay.google.com/gp/v/save/...",
"google_qrcode_url": "https://api.wallethero.app/...",
"date_created": "2024-01-15T10:30:00Z"
}
}SDK
const pass = await wh.passes.get("PASS_ID");Create Pass
POST /wallethero-api/workspace/:workspaceId/passes
Creates a pass. See Create Pass for full request body details.
SDK
const pass = await wh.passes.create({
workspace_id: "WORKSPACE_ID",
project_id: "PROJECT_ID",
pass_template_id: "TEMPLATE_ID",
client_id: "CLIENT_ID",
});Update Pass
PATCH /wallethero-api/passes/:id
Updates a pass. See Update Pass for the accepted fields.
SDK
await wh.passes.update("PASS_ID", { notification: "Welcome to Gold tier!" });Delete Pass
DELETE /wallethero-api/passes/:id
Deletes a pass.
Auth: Bearer token — member of the pass's workspace.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string (UUID) | Pass identifier |
Example Request
curl -X DELETE "https://api.wallethero.app/wallethero-api/passes/PASS_ID" \
-H "Authorization: Bearer YOUR_TOKEN"Response (200)
{ "message": "passes deleted" }SDK
await wh.passes.delete("PASS_ID");Aggregate Passes by Wallet
GET /wallethero-api/workspace/:workspaceId/passes/aggregate
Returns counts of passes installed in Apple vs Google Wallet for the workspace.
Auth: Bearer token — workspace member.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
workspaceId | string (UUID) | Workspace identifier |
Example Request
curl "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/passes/aggregate" \
-H "Authorization: Bearer YOUR_TOKEN"Response (200)
{ "data": { "total": 1280, "apple": 720, "google": 560 } }SDK
const stats = await wh.passes.aggregateByWallet("WORKSPACE_ID");Refresh All Passes
POST /wallethero-api/workspace/:workspaceId/passes/refresh-all
Queues a wallet refresh for every live pass in the workspace. The passserver fans out per pass_template_id. The response reports how many distinct templates were queued.
Auth: Bearer token — workspace member.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
workspaceId | string (UUID) | Workspace identifier |
Example Request
curl -X POST "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/passes/refresh-all" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{}'Response (200)
{ "data": { "queued": true, "templateCount": 4 } }SDK
const result = await wh.passes.refreshAllForWorkspace("WORKSPACE_ID");Loyalty Render Snapshot
GET /wallethero-api/workspace/:workspaceId/passes/:passId/loyalty-render-data
Returns the live loyalty render snapshot for a pass — wallets (one entry per active wallet type with the client's balance, name, unit names, and an is_default flag), tier, portal URL, tier benefits, and active/available rewards — exactly as the passserver renders it into the wallet pass. Used by the editor preview so ${wallet.points} resolves to the same value shown on the device.
Pass templates reference balances with ${wallet.points} (default wallet) or ${wallet:<code>.points} (a specific wallet by its code). Other per-wallet fields: name, unit_singular_name, unit_plural_name. The legacy ${loyalty.points} placeholder was removed; ${loyalty.tier}, ${loyalty.tier_level}, and ${loyalty.referral_code} are unchanged.
Auth: Bearer token — workspace member.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
workspaceId | string (UUID) | Workspace identifier |
passId | string (UUID) | Pass identifier |
Example Request
curl "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/passes/PASS_ID/loyalty-render-data" \
-H "Authorization: Bearer YOUR_TOKEN"SDK
const snapshot = await wh.passes.getLoyaltyRenderData("WORKSPACE_ID", "PASS_ID");Resend Pass Email
POST /wallethero-api/pass/resend
Re-sends the pass email to the holder, returning the Apple/Google pass URLs. Lives in the distribution route group; can be called with a valid Bearer token.
Auth: Bearer token.
Request Body
| Field | Type | Required | Description |
|---|---|---|---|
pass_id | string (UUID) | Yes | Pass to resend |
email | string (email) | No | Override recipient (defaults to the pass holder's email) |
email_template | string | No | Custom email HTML template |
Example Request
curl -X POST "https://api.wallethero.app/wallethero-api/pass/resend" \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{ "pass_id": "PASS_ID" }'Response (200)
{
"data": {
"pass_id": "pass-uuid",
"apple_pass_url": "https://api.wallethero.app/...",
"google_pass_url": "https://pay.google.com/gp/v/save/..."
},
"message": "Pass email resent successfully to [email protected]",
"success": true
}SDK
const result = await wh.passes.resendEmail("PASS_ID");
// with overrides:
await wh.passes.resendEmail("PASS_ID", customHtmlTemplate, "[email protected]");Pass Structure
interface Pass {
id: string;
pass_template_id: string;
project_id: string;
workspace_id: string;
client_id?: string | null;
// Populated only when the relation is expanded (?fields=*,client.*).
// Identity (first_name/last_name/email/phone) and custom_fields live here.
client?: Client | null;
notification?: string; // Last push notification message
pass_fields?: Record<string, any>; // Pass-display overrides (image overrides, etc.)
barcode_value?: string | null; // Pre-interpolated barcode value (read-only)
// Temporary template switch (loyalty)
template_expires_at?: string | null;
previous_template_id?: string | null;
computed_metrics?: Record<string, number>;
// Generated URLs (read-only)
apple_pass_url?: string;
apple_qrcode_url?: string;
google_pass_url?: string;
google_qrcode_url?: string;
// Metadata
date_created?: string;
date_updated?: string;
user_created?: string;
user_updated?: string;
}Identity & custom fields live on the client
A pass does not carry its own name/email or custom_fields. To read them, expand the related client:
GET /wallethero-api/passes/{pass_id}?fields=*,client.*To write them, update the client — see Pass Custom Fields and Clients.
Related Endpoints
- Create Pass —
POST /wallethero-api/workspace/:workspaceId/passes - Update Pass —
PATCH /wallethero-api/passes/:id - Pass Custom Fields — discovering field names and values
- Passes by project:
GET /wallethero-api/projects/:id/passes(see Projects)