Skip to content

Clients

Endpoints for managing clients (customers) within a workspace: list, search, create, update, delete, anonymize (GDPR), merge, signup analytics, plus per-client passes and a client-event timeline.

All endpoints are workspace-scoped and require the caller to be a member of the workspace named in the path (enforced by createWorkspaceGuard). Authenticate with a Bearer token in the Authorization header and send Content-Type: application/json.


List clients

GET /wallethero-api/workspace/:workspaceId/clients

Returns a paginated list of clients in the workspace, with optional filtering, free-text search, and sorting. Ordered by date_created descending unless sort is provided.

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Query Parameters

ParameterTypeRequiredDefaultDescription
searchstring (max 255)NoFree-text search across name / email / phone
statusstring enumNoOne of active, inactive, anonymized
sourcestring (max 50)NoFilter by acquisition source
emailstring (max 255)NoExact email match
from_datestring (ISO 8601)NoOnly clients created on/after this timestamp
to_datestring (ISO 8601)NoOnly clients created on/before this timestamp
limitnumberNo50Page size (1–1000)
offsetnumberNo0Pagination offset
sortstring (max 50)No-date_createdColumn to sort by; prefix with - for descending

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/clients?status=active&limit=25" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{
  "data": [
    {
      "id": "8f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
      "workspace_id": "WORKSPACE_ID",
      "first_name": "Jane",
      "last_name": "Doe",
      "email": "[email protected]",
      "phone": "+15551234567",
      "status": "active",
      "marketing_consent": true,
      "custom_fields": {},
      "registration_date": "2026-01-10T12:00:00.000Z",
      "date_created": "2026-01-10T12:00:00.000Z"
    }
  ],
  "meta": { "total": 142, "limit": 25, "offset": 0 }
}

SDK

typescript
const clients = await wh.clients.list(workspaceId, {
  status: "active",
  limit: 25,
});

Search clients

GET /wallethero-api/workspace/:workspaceId/clients/search

Free-text search across client name, email, and phone. A lighter-weight variant of list that returns a bare array (no meta).

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Query Parameters

ParameterTypeRequiredDefaultDescription
qstringYesSearch query. Returns 400 if missing
limitnumberNo10Max results

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/clients/search?q=jane&limit=5" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{
  "data": [
    {
      "id": "8f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
      "first_name": "Jane",
      "last_name": "Doe",
      "email": "[email protected]",
      "status": "active"
    }
  ]
}

SDK

No SDK method — call the REST endpoint directly. (The SDK's list with a search option uses the list endpoint instead.)


Create a client

POST /wallethero-api/workspace/:workspaceId/clients

Creates a new client in the workspace. Email must be unique within the workspace — a duplicate returns a validation error. Loyalty enrollment is opt-in via loyalty_program_enabled.

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Request Body

FieldTypeRequiredDescription
first_namestring (max 255)No
last_namestring (max 255)No
emailstring (email, max 255)NoMust be unique in the workspace
phonestring (max 50)No
birth_datestring (YYYY-MM-DD)No
marketing_consentbooleanNoDefaults to false. When explicitly provided, the server stamps consent provenance on the client: marketing_consent_at (now), marketing_consent_source (api) and marketing_consent_text
marketing_consent_textstring (max 2000)NoSnapshot of the consent wording shown to the person (GDPR demonstrability). Only stored alongside a marketing_consent decision
custom_fieldsobjectNoArbitrary key/value JSON
statusstring enumNoactive (default), inactive, or anonymized
sourcestring (max 50)NoAcquisition source label
loyalty_program_enabledbooleanNoEnrolls the client in loyalty when true

Example Request

bash
curl -X POST "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/clients" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "[email protected]",
    "marketing_consent": true
  }'

Response (201)

json
{
  "data": {
    "id": "8f1c2d3e-4a5b-6c7d-8e9f-0a1b2c3d4e5f",
    "workspace_id": "WORKSPACE_ID",
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "[email protected]",
    "marketing_consent": true,
    "custom_fields": {},
    "status": "active",
    "registration_date": "2026-06-16T10:00:00.000Z",
    "date_created": "2026-06-16T10:00:00.000Z"
  }
}

SDK

typescript
const client = await wh.clients.create(workspaceId, {
  first_name: "Jane",
  last_name: "Doe",
  email: "[email protected]",
  marketing_consent: true,
});

Merge two clients

POST /wallethero-api/workspace/:workspaceId/clients/merge

Merges a source client into a target client: passes, events, wallets (with ledger/balance reconciliation), tiers (keeping the higher tier), automation executions, and reward redemptions are moved to the target. Missing scalar fields on the target are backfilled from the source, custom fields are merged (target wins), and the source client is deleted. Returns the resulting target client.

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Request Body

FieldTypeRequiredDescription
source_client_idstring (UUID)YesClient to merge from (deleted afterwards)
target_client_idstring (UUID)YesClient to merge into (survives)

Both clients must exist in the workspace, and the two IDs must differ.

Example Request

bash
curl -X POST "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/clients/merge" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "source_client_id": "11111111-1111-1111-1111-111111111111",
    "target_client_id": "22222222-2222-2222-2222-222222222222"
  }'

Response (200)

json
{
  "data": {
    "id": "22222222-2222-2222-2222-222222222222",
    "workspace_id": "WORKSPACE_ID",
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "[email protected]",
    "status": "active"
  }
}

SDK

No SDK method — call the REST endpoint directly.


Signup buckets

POST /wallethero-api/workspace/:workspaceId/clients/signup-buckets

Returns counts of new clients grouped into time buckets over a date range, for dashboards. Includes the total, the latest bucket's count, and week-over-week growth.

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Request Body

FieldTypeRequiredDescription
from_datestring (ISO 8601)NoStart of range (filters on date_created)
to_datestring (ISO 8601)NoEnd of range
group_by_timestring enumNoday, week (default), or month

Example Request

bash
curl -X POST "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/clients/signup-buckets" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "from_date": "2026-01-01T00:00:00.000Z",
    "to_date": "2026-06-16T00:00:00.000Z",
    "group_by_time": "week"
  }'

Response (200)

json
{
  "data": {
    "buckets": [
      { "date": "2026-01-05T00:00:00.000Z", "count": 12 },
      { "date": "2026-01-12T00:00:00.000Z", "count": 18 }
    ],
    "total": 30,
    "latest_bucket_count": 18,
    "growth_wow_pct": 50
  }
}

SDK

typescript
const result = await wh.clients.getSignupBuckets(workspaceId, {
  from_date: "2026-01-01T00:00:00.000Z",
  to_date: "2026-06-16T00:00:00.000Z",
  group_by_time: "week",
});

Get a single client

GET /wallethero-api/workspace/:workspaceId/clients/:id

Fetches one client by ID. Returns a not-found error if the client does not belong to the workspace.

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier
idstring (UUID)Client identifier

Example Request

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

Response (200)

json
{
  "data": {
    "id": "CLIENT_ID",
    "workspace_id": "WORKSPACE_ID",
    "first_name": "Jane",
    "last_name": "Doe",
    "email": "[email protected]",
    "phone": "+15551234567",
    "status": "active",
    "marketing_consent": true,
    "custom_fields": {},
    "loyalty_program_enabled": false,
    "date_created": "2026-01-10T12:00:00.000Z"
  }
}

SDK

typescript
const client = await wh.clients.get(workspaceId, clientId);

Update a client

PATCH /wallethero-api/workspace/:workspaceId/clients/:id

Partially updates a client. Scalar fields may be set to null to clear them. Changing the email to one already used in the workspace returns a validation error. Field changes emit field_change events (source api), and toggling loyalty_program_enabled additionally re-evaluates the client's tier.

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier
idstring (UUID)Client identifier

Request Body

All fields optional; only the provided fields are changed.

FieldTypeNullableDescription
first_namestring (max 255)Yes
last_namestring (max 255)Yes
emailstring (email, max 255)YesMust remain unique in the workspace
phonestring (max 50)Yes
birth_datestring (YYYY-MM-DD)Yes
marketing_consentbooleanNoConsent provenance (marketing_consent_at, marketing_consent_source: "api", marketing_consent_text) is stamped server-side, and only on an actual value change
marketing_consent_textstring (max 2000)NoSnapshot of the consent wording shown to the person; stored only when marketing_consent changes
custom_fieldsobjectNoMerged into existing custom fields
statusstring enumNoactive, inactive, or anonymized
sourcestring (max 50)Yes
loyalty_program_enabledbooleanNoToggling re-evaluates the client's tier

Example Request

bash
curl -X PATCH "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/clients/CLIENT_ID" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "phone": "+15559998888", "loyalty_program_enabled": true }'

Response (200)

json
{
  "data": {
    "id": "CLIENT_ID",
    "workspace_id": "WORKSPACE_ID",
    "phone": "+15559998888",
    "loyalty_program_enabled": true,
    "status": "active"
  }
}

SDK

typescript
const client = await wh.clients.update(workspaceId, clientId, {
  phone: "+15559998888",
  loyalty_program_enabled: true,
});

Delete a client

DELETE /wallethero-api/workspace/:workspaceId/clients/:id

Permanently deletes a client and their passes. For every provider the client has an external identity with, a durable delete_customer outbound job is enqueued so the deletion is mirrored to integrated systems (the job snapshot carries only the identifiers needed for the remote delete — no name/email). The client's events are retained for audit, but scrubbed of PII first: old_value/new_value are nulled on every field_change event except non-PII fields (status, marketing_consent), and client_name_snapshot is set to the anonymized label Deleted client instead of the real name. Orphaned events (their client_id becomes NULL) are purged by the daily retention cron after RETENTION_ORPHANED_CLIENT_EVENTS_DAYS (default 365).

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier
idstring (UUID)Client identifier

Example Request

bash
curl -X DELETE "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/clients/CLIENT_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{ "message": "Client deleted successfully" }

SDK

typescript
const result = await wh.clients.delete(workspaceId, clientId);
// => { message: "Client deleted successfully" }

Anonymize a client (GDPR)

POST /wallethero-api/workspace/:workspaceId/clients/:id/anonymize

Anonymizes a client for GDPR: nulls identity fields (first_name, last_name, email, phone, birth_date), clears all custom fields, records marketing_consent: false with source anonymize, disables loyalty-program eligibility, and sets status to anonymized. Existing loyalty-portal tokens are rejected because every authenticated portal request re-checks active client status, and campaign audiences independently require status: active. Each cleared field emits a field_change event (source anonymize). The client row and its history are retained, but the event trail is scrubbed: old_value/new_value are nulled on every field_change event (including the ones just emitted by the anonymization itself) except the non-PII fields status and marketing_consent, and any client_name_snapshot is cleared.

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier
idstring (UUID)Client identifier

Example Request

bash
curl -X POST "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/clients/CLIENT_ID/anonymize" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{
  "data": {
    "id": "CLIENT_ID",
    "workspace_id": "WORKSPACE_ID",
    "first_name": null,
    "last_name": null,
    "email": null,
    "phone": null,
    "birth_date": null,
    "custom_fields": {},
    "marketing_consent": false,
    "loyalty_program_enabled": false,
    "status": "anonymized"
  }
}

SDK

typescript
const client = await wh.clients.anonymize(workspaceId, clientId);

Get passes for a client

GET /wallethero-api/workspace/:workspaceId/clients/:id/passes

Returns all wallet passes belonging to the client, newest first.

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier
idstring (UUID)Client identifier

Example Request

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

Response (200)

json
{
  "data": [
    {
      "id": "aaaa1111-2222-3333-4444-555566667777",
      "client_id": "CLIENT_ID",
      "date_created": "2026-02-01T08:30:00.000Z"
    }
  ]
}

SDK

typescript
const passes = await wh.clients.getPasses(workspaceId, clientId);

Create a client event

POST /wallethero-api/workspace/:workspaceId/client-events

Records a custom event on the client timeline. The workspace is derived from the client; the caller must have access to that workspace.

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Request Body

FieldTypeRequiredDescription
client_idstring (UUID)YesClient the event belongs to
event_categorystring enumYesOne of field_change, transaction, activity, loyalty
event_typestring (1–50 chars)YesApplication-defined event type
event_timestampstring (ISO 8601)NoDefaults to now
amountnumberNoFor transaction-style events
currencystring (3 chars)NoISO currency code
field_namestring (max 100)NoFor field-change events
old_valuestring | nullNo
new_valuestring | nullNo
metadataobjectNoArbitrary JSON
external_idstring (max 255)NoIdempotency / external reference
sourcestring (max 100)NoOrigin label
pass_idstring (UUID)NoAssociated pass

Example Request

bash
curl -X POST "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/client-events" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "client_id": "CLIENT_ID",
    "event_category": "transaction",
    "event_type": "purchase",
    "amount": 49.99,
    "currency": "USD"
  }'

Response (200)

json
{
  "data": {
    "id": "eeee1111-2222-3333-4444-555566667777",
    "workspace_id": "WORKSPACE_ID",
    "client_id": "CLIENT_ID",
    "event_category": "transaction",
    "event_type": "purchase",
    "event_timestamp": "2026-06-16T10:00:00.000Z",
    "amount": 49.99,
    "currency": "USD",
    "metadata": {}
  }
}

SDK

typescript
const event = await wh.clients.createEvent(workspaceId, {
  client_id: clientId,
  event_category: "transaction",
  event_type: "purchase",
  amount: 49.99,
  currency: "USD",
});

List client events

GET /wallethero-api/workspace/:workspaceId/client-events

Returns events across all clients in the workspace, newest first, with optional filtering. To fetch events for one client, use the per-client variant below.

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Query Parameters

ParameterTypeRequiredDefaultDescription
client_idstring (UUID)NoRestrict to a single client
event_categorystring enumNofield_change, transaction, activity, or loyalty
event_typesstring (CSV)NoComma-separated list of event types
from_datestring (ISO 8601)NoFilters on event_timestamp
to_datestring (ISO 8601)NoFilters on event_timestamp
sourcestring (max 100)NoFilter by event source
limitnumberNo100Page size (1–1000)
offsetnumberNo0Pagination offset

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/client-events?event_category=transaction&limit=50" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{
  "data": [
    {
      "id": "eeee1111-2222-3333-4444-555566667777",
      "client_id": "CLIENT_ID",
      "event_category": "transaction",
      "event_type": "purchase",
      "event_timestamp": "2026-06-16T10:00:00.000Z",
      "amount": 49.99,
      "currency": "USD"
    }
  ],
  "meta": { "total_count": 320, "returned_count": 50, "offset": 0 }
}

SDK

No SDK method for the workspace-wide listing — use wh.clients.listEvents(workspaceId, clientId, ...) for a single client, or call this REST endpoint directly.


Get events for a specific client

GET /wallethero-api/workspace/:workspaceId/clients/:id/events

Returns the event timeline for one client, newest first. Same filters as the workspace-wide listing, scoped to the client in the path.

Auth: Bearer token — workspace member.

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier
idstring (UUID)Client identifier

Query Parameters

ParameterTypeRequiredDefaultDescription
event_categorystring enumNofield_change, transaction, activity, or loyalty
event_typesstring (CSV)NoComma-separated list of event types
from_datestring (ISO 8601)NoFilters on event_timestamp
to_datestring (ISO 8601)NoFilters on event_timestamp
sourcestring (max 100)NoFilter by event source
limitnumberNo100Page size (1–1000)
offsetnumberNo0Pagination offset

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/clients/CLIENT_ID/events?limit=50" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{
  "data": [
    {
      "id": "eeee1111-2222-3333-4444-555566667777",
      "client_id": "CLIENT_ID",
      "event_category": "loyalty",
      "event_type": "tier_promoted",
      "event_timestamp": "2026-06-16T10:00:00.000Z"
    }
  ],
  "meta": { "total_count": 27, "returned_count": 27, "offset": 0 }
}

SDK

typescript
const events = await wh.clients.listEvents(workspaceId, clientId, {
  event_category: "loyalty",
  limit: 50,
});

WalletHero Documentation