Skip to content

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

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/passes" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{
  "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

typescript
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

ParameterTypeDescription
idstring (UUID)Pass identifier

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/passes/PASS_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{
  "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

typescript
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

typescript
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

typescript
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

ParameterTypeDescription
idstring (UUID)Pass identifier

Example Request

bash
curl -X DELETE "https://api.wallethero.app/wallethero-api/passes/PASS_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{ "message": "passes deleted" }

SDK

typescript
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

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/passes/aggregate" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{ "data": { "total": 1280, "apple": 720, "google": 560 } }

SDK

typescript
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

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Example Request

bash
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)

json
{ "data": { "queued": true, "templateCount": 4 } }

SDK

typescript
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

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier
passIdstring (UUID)Pass identifier

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/passes/PASS_ID/loyalty-render-data" \
  -H "Authorization: Bearer YOUR_TOKEN"

SDK

typescript
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

FieldTypeRequiredDescription
pass_idstring (UUID)YesPass to resend
emailstring (email)NoOverride recipient (defaults to the pass holder's email)
email_templatestringNoCustom email HTML template

Example Request

bash
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)

json
{
  "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

typescript
const result = await wh.passes.resendEmail("PASS_ID");
// with overrides:
await wh.passes.resendEmail("PASS_ID", customHtmlTemplate, "[email protected]");

Pass Structure

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

  • Create PassPOST /wallethero-api/workspace/:workspaceId/passes
  • Update PassPATCH /wallethero-api/passes/:id
  • Pass Custom Fields — discovering field names and values
  • Passes by project: GET /wallethero-api/projects/:id/passes (see Projects)

WalletHero Documentation