Skip to content

Transactions

Transactions record purchases (and walk-in / anonymous sales) for a workspace, drive loyalty processing (points awarded/spent, applied rewards and automation rules), and back the analytics endpoints (AOV, member-vs-walkin mix, AOV by tier, aggregations).

Unlike most WalletHero resources, these endpoints are not workspace-path-scoped in the URL. The workspace is identified by a workspace_id value supplied in the query string (GET endpoints) or the request body (POST/PATCH/DELETE), and the route guard verifies the caller is a member of that workspace before the handler runs. All endpoints require a Bearer token; the token's user must belong to the named workspace.


List transactions

GET /wallethero-api/transactions

Returns transactions for a workspace, newest first, with rich filtering and pagination. Includes a meta block with total/filtered counts.

Auth: Bearer token — workspace member (workspace resolved from workspace_id query param).

Query Parameters

ParameterTypeRequiredDefaultDescription
workspace_idstring (UUID)YesWorkspace to query
client_idstring (UUID)NoFilter to a single client
pass_idstring (UUID)NoFilter to a single pass
client_searchstringNoFree-text client search; matches transactions whose client matches
from_datestring (ISO 8601)NoOnly transactions at/after this timestamp
to_datestring (ISO 8601)NoOnly transactions at/before this timestamp
sourcestringNoExact match on the transaction source
locationstringNoExact match on the transaction location
min_amountnumberNoMinimum amount (inclusive)
max_amountnumberNoMaximum amount (inclusive)
external_idstringNoExact match on external id
is_anonymousbooleanNoFilter walk-in (true) vs identified (false)
loyalty_appliedbooleanNoFilter rows where loyalty was applied
tier_idstring (UUID)NoOnly clients currently in this tier
limitnumberNo50Page size (1–1000)
offsetnumberNo0Row offset (≥ 0)

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/transactions?workspace_id=WORKSPACE_ID&limit=20&is_anonymous=false" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{
  "data": [
    {
      "id": "8f3c2a10-1234-4a5b-9c0d-aabbccddeeff",
      "workspace_id": "WORKSPACE_ID",
      "client_id": "11111111-1111-1111-1111-111111111111",
      "pass_id": "22222222-2222-2222-2222-222222222222",
      "amount": 49.9,
      "currency": "USD",
      "description": "Coffee + pastry",
      "external_id": "POS-1001",
      "source": "idpos",
      "location": "Downtown",
      "transaction_timestamp": "2026-06-10T14:30:00.000Z",
      "line_items": [{ "name": "Latte", "quantity": 1, "unit_price": 4.5, "total": 4.5 }],
      "payment_info": { "method": "card" },
      "metadata": {},
      "is_anonymous": false,
      "subtotal_amount": 49.9,
      "discount_amount": 0,
      "points_awarded": 50,
      "points_spent": 0,
      "applied_rewards": [],
      "applied_automation_rules": [],
      "loyalty_applied": true
    }
  ],
  "meta": { "total_count": 134, "filter_count": 134 }
}

SDK

typescript
const { data, meta } = await wh.transactions.list({
  workspace_id: workspaceId,
  is_anonymous: false,
  limit: 20,
});

AOV breakdown

GET /wallethero-api/transactions/aov

Computes average order value (AOV) for the workspace, broken down three ways: overall, by identification (identified vs anonymous), and by whether loyalty was applied. Only transactions with amount >= 0 are counted.

Auth: Bearer token — workspace member (workspace_id query param).

Query Parameters

ParameterTypeRequiredDefaultDescription
workspace_idstring (UUID)YesWorkspace to query
from_datestring (ISO 8601)NoOnly transactions at/after this timestamp
to_datestring (ISO 8601)NoOnly transactions at/before this timestamp
sourcestringNoExact match on the transaction source
currencystring (3-letter)NoRestrict to a single currency

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/transactions/aov?workspace_id=WORKSPACE_ID&from_date=2026-01-01T00:00:00.000Z" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{
  "data": {
    "overall": { "count": 134, "total": 6700.5, "aov": 50.0 },
    "by_identification": {
      "identified": { "count": 90, "total": 4950.0, "aov": 55.0 },
      "anonymous": { "count": 44, "total": 1750.5, "aov": 39.78 }
    },
    "by_loyalty_applied": {
      "applied": { "count": 90, "total": 4950.0, "aov": 55.0 },
      "not_applied": { "count": 44, "total": 1750.5, "aov": 39.78 }
    }
  }
}

SDK

typescript
const { data } = await wh.transactions.getAov({
  workspace_id: workspaceId,
  from_date: "2026-01-01T00:00:00.000Z",
});

List transaction sources

GET /wallethero-api/transactions/sources

Returns the distinct, non-null source values present on the workspace's transactions, sorted alphabetically. Useful for building filter dropdowns.

Auth: Bearer token — workspace member (workspace_id query param).

Query Parameters

ParameterTypeRequiredDefaultDescription
workspace_idstring (UUID)YesWorkspace to query

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/transactions/sources?workspace_id=WORKSPACE_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{ "data": ["idpos", "manual", "shopify"] }

SDK

typescript
const { data: sources } = await wh.transactions.getSources(workspaceId);

List transaction locations

GET /wallethero-api/transactions/locations

Returns the distinct, non-null location values present on the workspace's transactions, sorted alphabetically.

Auth: Bearer token — workspace member (workspace_id query param).

Query Parameters

ParameterTypeRequiredDefaultDescription
workspace_idstring (UUID)YesWorkspace to query

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/transactions/locations?workspace_id=WORKSPACE_ID" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{ "data": ["Downtown", "Mall", "Online"] }

SDK

typescript
const { data: locations } = await wh.transactions.getLocations(workspaceId);

Bulk-assign client to transactions

POST /wallethero-api/transactions/assign-client

Assigns a client to one or more anonymous/unassigned transactions. Only rows that are is_anonymous = true or have client_id IS NULL are eligible; already-identified rows are silently skipped and reported back in skipped_ids. Assigning a client emits the same downstream events as a new transaction (automation-rule processing, tier progression, webhook fan-out).

Auth: Bearer token — workspace member (workspace resolved from workspace_id in body). The target client must exist in that workspace.

Request Body

FieldTypeRequiredDescription
idsstring[] (UUID)YesTransaction ids to assign (1–1000)
workspace_idstring (UUID)YesWorkspace the transactions and client belong to
client_idstring (UUID)YesClient to assign

Example Request

bash
curl -X POST "https://api.wallethero.app/wallethero-api/transactions/assign-client" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": ["8f3c2a10-1234-4a5b-9c0d-aabbccddeeff"],
    "workspace_id": "WORKSPACE_ID",
    "client_id": "11111111-1111-1111-1111-111111111111"
  }'

Response (200)

json
{
  "data": {
    "assigned": 1,
    "skipped": 0,
    "skipped_ids": []
  }
}

SDK

typescript
const { data } = await wh.transactions.assignClient({
  ids: ["8f3c2a10-1234-4a5b-9c0d-aabbccddeeff"],
  workspace_id: workspaceId,
  client_id: clientId,
});

Update a transaction (assign client)

PATCH /wallethero-api/transactions/:id

Updates a single transaction. Currently this is restricted to assigning a client to an anonymous/unassigned transaction. The body's workspace_id is guarded; the service then verifies the transaction belongs to that workspace and that the client exists in it. Returns 400 if the transaction is already assigned to a client or not found in the workspace.

Auth: Bearer token — workspace member (workspace resolved from workspace_id in body).

Path Parameters

ParameterTypeDescription
idstring (UUID)Transaction id

Request Body

FieldTypeRequiredDescription
workspace_idstring (UUID)YesWorkspace the transaction and client belong to
client_idstring (UUID)YesClient to assign

Example Request

bash
curl -X PATCH "https://api.wallethero.app/wallethero-api/transactions/8f3c2a10-1234-4a5b-9c0d-aabbccddeeff" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "WORKSPACE_ID",
    "client_id": "11111111-1111-1111-1111-111111111111"
  }'

Response (200)

json
{
  "data": {
    "id": "8f3c2a10-1234-4a5b-9c0d-aabbccddeeff",
    "workspace_id": "WORKSPACE_ID",
    "client_id": "11111111-1111-1111-1111-111111111111",
    "is_anonymous": false,
    "amount": 49.9,
    "currency": "USD",
    "loyalty_applied": true
  }
}

SDK

typescript
const { data } = await wh.transactions.update(transactionId, {
  workspace_id: workspaceId,
  client_id: clientId,
});

Get a transaction

GET /wallethero-api/transactions/:id

Returns a single transaction by id. The route guard loads the transaction and verifies the caller is a member of its workspace (no workspace_id query param is required for this endpoint).

Auth: Bearer token — workspace member (workspace resolved from the transaction's own workspace_id).

Path Parameters

ParameterTypeDescription
idstring (UUID)Transaction id

Example Request

bash
curl "https://api.wallethero.app/wallethero-api/transactions/8f3c2a10-1234-4a5b-9c0d-aabbccddeeff" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{
  "data": {
    "id": "8f3c2a10-1234-4a5b-9c0d-aabbccddeeff",
    "workspace_id": "WORKSPACE_ID",
    "client_id": "11111111-1111-1111-1111-111111111111",
    "pass_id": "22222222-2222-2222-2222-222222222222",
    "amount": 49.9,
    "currency": "USD",
    "description": "Coffee + pastry",
    "external_id": "POS-1001",
    "source": "idpos",
    "location": "Downtown",
    "transaction_timestamp": "2026-06-10T14:30:00.000Z",
    "line_items": [],
    "payment_info": { "method": "card" },
    "metadata": {},
    "is_anonymous": false,
    "subtotal_amount": 49.9,
    "discount_amount": 0,
    "points_awarded": 50,
    "points_spent": 0,
    "applied_rewards": [],
    "applied_automation_rules": [],
    "loyalty_applied": true
  }
}

SDK

typescript
const { data } = await wh.transactions.get(transactionId);

Create a transaction

POST /wallethero-api/transactions

Creates a transaction and runs the loyalty pipeline. The transaction can be tied to a client directly (client_id), via a pass (pass_id, whose client and workspace are resolved automatically), or recorded as an anonymous walk-in (is_anonymous = true, which requires workspace_id). When workspace_id is omitted it is derived from the pass or client; in that case the workspace-membership check still runs against the resolved workspace.

loyalty_applied is computed automatically (true when any discount, points spent, points awarded, applied rewards, or applied automation rules are present). points_awarded is summed from applied_automation_rules[].points_awarded. Currency falls back to the workspace default, then "USD". If a row with the same (workspace_id, source, external_id) already exists, the existing transaction is returned (idempotent on redelivery).

Auth: Bearer token — workspace member (workspace resolved from workspace_id in body, or derived from pass_id / client_id).

Request Body

FieldTypeRequiredDescription
amountnumberYesTransaction total
workspace_idstring (UUID)ConditionalRequired for anonymous transactions; otherwise derived from pass/client if omitted
client_idstring (UUID)ConditionalIdentifies the client; one of client_id, pass_id, or is_anonymous=true is required
pass_idstring (UUID)ConditionalResolves client + workspace from the pass
is_anonymousbooleanConditionaltrue for walk-in/anonymous sales (forces client_id = null)
currencystring (3-letter)NoDefaults to workspace currency, then "USD"
descriptionstring (≤ 2000)NoFree-text description
external_idstring (≤ 255)NoExternal system id (used for dedupe with source)
sourcestring (≤ 100)NoOrigin system (e.g. idpos, manual)
locationstring (≤ 255)NoStore / location label
transaction_timestampstring (ISO 8601)NoDefaults to now
line_itemsLineItem[]No{ name, quantity, unit_price, total, sku? }
payment_infoobjectNo{ method?, provider?, reference?, ... }
metadataobjectNoArbitrary key/value metadata
subtotal_amountnumberNoPre-discount subtotal
discount_amountnumberNoDefaults to 0
points_spentnumberNoDefaults to 0
applied_rewardsAppliedReward[]No{ reward_redemption_id, reward_id, name, monetary_value, points_spent }
applied_automation_rulesAppliedAutomationRule[]No{ earning_rule_execution_id, earning_rule_id, name, points_awarded }

Example Request

bash
curl -X POST "https://api.wallethero.app/wallethero-api/transactions" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "WORKSPACE_ID",
    "client_id": "11111111-1111-1111-1111-111111111111",
    "amount": 49.9,
    "currency": "USD",
    "source": "manual",
    "description": "Coffee + pastry"
  }'

Response (200)

json
{
  "data": {
    "id": "8f3c2a10-1234-4a5b-9c0d-aabbccddeeff",
    "workspace_id": "WORKSPACE_ID",
    "client_id": "11111111-1111-1111-1111-111111111111",
    "amount": 49.9,
    "currency": "USD",
    "is_anonymous": false,
    "discount_amount": 0,
    "points_awarded": 0,
    "points_spent": 0,
    "applied_rewards": [],
    "applied_automation_rules": [],
    "loyalty_applied": false,
    "transaction_timestamp": "2026-06-16T09:00:00.000Z"
  }
}

SDK

typescript
const { data } = await wh.transactions.create({
  workspace_id: workspaceId,
  client_id: clientId,
  amount: 49.9,
  currency: "USD",
  source: "manual",
});

Member-vs-walkin mix

POST /wallethero-api/transactions/mix

Returns the member (identified) vs walk-in (anonymous) split of transactions, with totals, AOV, and time-bucketed series for each slice. Buckets default to daily.

Auth: Bearer token — workspace member (workspace_id in body).

Request Body

FieldTypeRequiredDefaultDescription
workspace_idstring (UUID)YesWorkspace to query
client_idstring (UUID)NoFilter to a client
client_searchstringNoFree-text client search filter
from_datestring (ISO 8601)NoLower time bound
to_datestring (ISO 8601)NoUpper time bound
sourcestringNoExact source match
locationstringNoExact location match
min_amountnumberNoMinimum amount (inclusive)
max_amountnumberNoMaximum amount (inclusive)
is_anonymousbooleanNoRestrict to anonymous/identified
loyalty_appliedbooleanNoRestrict by loyalty-applied flag
tier_idstring (UUID)NoRestrict to clients currently in this tier
group_by_time"day" | "week" | "month"No"day"Bucket size

Example Request

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

Response (200)

json
{
  "data": {
    "member": {
      "total_count": 90,
      "total_sum": 4950.0,
      "aov": 55.0,
      "buckets": [
        { "date": "2026-06-01T00:00:00.000Z", "count": 40, "sum": 2200.0, "aov": 55.0 }
      ]
    },
    "walkin": {
      "total_count": 44,
      "total_sum": 1750.5,
      "aov": 39.78,
      "buckets": [
        { "date": "2026-06-01T00:00:00.000Z", "count": 20, "sum": 800.0, "aov": 40.0 }
      ]
    }
  }
}

SDK

typescript
const { data } = await wh.transactions.getMix({
  workspace_id: workspaceId,
  from_date: "2026-06-01T00:00:00.000Z",
  group_by_time: "week",
});

AOV by tier

POST /wallethero-api/transactions/aov-by-tier

Returns member-transaction AOV grouped by the client's current tier (read live from the workspace's tier set, not snapshotted on the transaction), plus a walk-in baseline AOV and an overall member AOV. Members with no tier are reported under tier_name: "Untiered" (tier_id: null). If the workspace has no tier set, tiers is empty.

Auth: Bearer token — workspace member (workspace_id in body).

Request Body

FieldTypeRequiredDescription
workspace_idstring (UUID)YesWorkspace to query
from_datestring (ISO 8601)NoLower time bound
to_datestring (ISO 8601)NoUpper time bound

Example Request

bash
curl -X POST "https://api.wallethero.app/wallethero-api/transactions/aov-by-tier" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "workspace_id": "WORKSPACE_ID" }'

Response (200)

json
{
  "data": {
    "tiers": [
      {
        "tier_id": "33333333-3333-3333-3333-333333333333",
        "tier_name": "Gold",
        "tier_color": "#FFD700",
        "tx_count": 30,
        "total_sum": 2100.0,
        "aov": 70.0
      },
      {
        "tier_id": null,
        "tier_name": "Untiered",
        "tier_color": null,
        "tx_count": 12,
        "total_sum": 480.0,
        "aov": 40.0
      }
    ],
    "walkin_baseline_aov": 39.78,
    "member_overall_aov": 55.0
  }
}

SDK

typescript
const { data } = await wh.transactions.getAovByTier({
  workspace_id: workspaceId,
});

Aggregate transactions

POST /wallethero-api/transactions/aggregate

Runs a single aggregation (count, sum, avg, min, or max over amount) across filtered transactions, optionally bucketed by time. count ignores amount; the others operate on the amount column.

Auth: Bearer token — workspace member (workspace_id in body).

Request Body

FieldTypeRequiredDescription
workspace_idstring (UUID)YesWorkspace to query
function"count" | "sum" | "avg" | "min" | "max"YesAggregation function
client_idstring (UUID)NoFilter to a client
from_datestring (ISO 8601)NoLower time bound
to_datestring (ISO 8601)NoUpper time bound
sourcestringNoExact source match
is_anonymousbooleanNoRestrict to anonymous/identified
loyalty_appliedbooleanNoRestrict by loyalty-applied flag
group_by_time"day" | "week" | "month"NoIf set, also returns per-bucket values

Example Request

bash
curl -X POST "https://api.wallethero.app/wallethero-api/transactions/aggregate" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "workspace_id": "WORKSPACE_ID",
    "function": "sum",
    "group_by_time": "month"
  }'

Response (200)

json
{
  "data": {
    "value": 6700.5,
    "buckets": [
      { "date": "2026-05-01T00:00:00.000Z", "value": 3100.0 },
      { "date": "2026-06-01T00:00:00.000Z", "value": 3600.5 }
    ]
  }
}

SDK

typescript
const { data } = await wh.transactions.aggregate({
  workspace_id: workspaceId,
  function: "sum",
  group_by_time: "month",
});

Batch-delete transactions

DELETE /wallethero-api/transactions/batch

Permanently deletes the given transactions within a workspace. Only ids that belong to workspace_id are removed; the response reports how many rows were actually deleted.

Auth: Bearer token — workspace member (workspace_id in body).

Request Body

FieldTypeRequiredDescription
idsstring[] (UUID)YesTransaction ids to delete (1–1000)
workspace_idstring (UUID)YesWorkspace the transactions belong to

Example Request

bash
curl -X DELETE "https://api.wallethero.app/wallethero-api/transactions/batch" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "ids": ["8f3c2a10-1234-4a5b-9c0d-aabbccddeeff"],
    "workspace_id": "WORKSPACE_ID"
  }'

Response (200)

json
{ "data": { "deleted": 1 } }

SDK

typescript
const { data } = await wh.transactions.deleteBatch(
  ["8f3c2a10-1234-4a5b-9c0d-aabbccddeeff"],
  workspaceId,
);

WalletHero Documentation