Skip to content

Referrals

Endpoints for configuring a workspace's referral program, browsing referral records, stats and analytics, managing individual referrals (cancel / manual complete), and fetching a single client's referral code, share link and counts. All endpoints are workspace-scoped and require Bearer-token auth from a member of the workspace.

How referrals work

  • A client shares their referral code (or the ?ref= share link). When a new client — or an existing client joining the loyalty program for the first time — enrolls through a distribution/embed form with that code, a pending referral is created. The submit response reports the attribution outcome (see below).
  • The referral completes when the referee meets the program's completion_criteria: pass_install (wallet pass installed) or first_transaction (first purchase with amount > 0, dated after the referral was created). Completion requires the program to be enabled and the referrer to be below max_referrals_per_referrer.
  • On completion, two referral_completed client events are published (one per role: referrer / referee; the referrer event carries referrer_completed_count), which drive reward automations (referral trigger). Events are delivered through a durable outbox — a crash cannot lose the reward. When a pending referral passes pending_expiry_days, it flips to expired and referral_expired events are published.
  • Referral codes are only minted for clients enrolled in the loyalty program. Disabling the program pauses pending referrals (they resume completing if re-enabled); deleting the program cancels them.
  • Deleting a client anonymizes their referral history (rows are kept with a null client reference) so stats stay stable.

Attribution outcomes (distribution / embed submit)

POST /wallethero-api/distribution/submit and POST /wallethero-api/embed/distribution/:token/submit responses include referral: { outcome } whenever a referral_code was submitted. An invalid or oversized code never fails the enrollment.

OutcomeMeaning
appliedPending referral created
invalid_codeCode unknown in this workspace (or empty after trimming)
program_disabledReferral program is off
self_referralCode belongs to the submitter (same client or email)
referrer_not_enrolledCode owner is not a loyalty member
referrer_at_capCode owner reached max_referrals_per_referrer
already_attributedThe referee already has a referral
not_eligibleExisting client already enrolled in loyalty — not a new referral
errorAttribution failed unexpectedly (enrollment still succeeded)

Get Referral Program

GET /wallethero-api/workspace/:workspaceId/referral-program

Returns the workspace's referral program settings (a single row per workspace). Responds 404 if no program has been configured yet.

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/referral-program" \
  -H "Authorization: Bearer YOUR_TOKEN"

Response (200)

json
{
  "data": {
    "id": "a1b2c3d4-0000-0000-0000-000000000001",
    "workspace_id": "WORKSPACE_ID",
    "enabled": true,
    "completion_criteria": "first_transaction",
    "distribution_id": "d4c3b2a1-0000-0000-0000-000000000002",
    "pending_expiry_days": 30,
    "max_referrals_per_referrer": 10,
    "date_created": "2026-01-10T12:00:00.000Z",
    "date_updated": "2026-02-01T08:30:00.000Z"
  }
}

Response (404)

json
{
  "errors": [
    { "message": "Referral program not configured", "extensions": { "code": "NOT_FOUND" } }
  ]
}

SDK

typescript
const { data: program } = await wh.referrals.getProgram(workspaceId);

Create or Update Referral Program

PUT /wallethero-api/workspace/:workspaceId/referral-program

Upserts the workspace's referral program settings. If a program already exists it is updated; otherwise a new one is created.

Disabling a program pauses its pending referrals — they stop completing but resume if the program is re-enabled.

Auth: Bearer token — workspace member

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Request Body

FieldTypeRequiredDescription
enabledbooleanYesWhether the referral program is active
completion_criteria"pass_install" | "first_transaction"YesThe event that marks a referral as completed. (enrollment was retired: instant completion at signup was abusable.)
distribution_idstring (UUID) | nullNoDistribution landing page used to build referral share links
pending_expiry_daysnumber | nullNoDays a pending referral stays valid before expiring (integer, 1–3650)
max_referrals_per_referrernumber | nullNoCap on completed referrals per referrer (positive integer). Enforced at attribution and completion.

Example Request

bash
curl -X PUT "https://api.wallethero.app/wallethero-api/workspace/WORKSPACE_ID/referral-program" \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "enabled": true,
    "completion_criteria": "first_transaction",
    "distribution_id": "d4c3b2a1-0000-0000-0000-000000000002",
    "pending_expiry_days": 30,
    "max_referrals_per_referrer": 10
  }'

Response (200)

json
{
  "data": {
    "id": "a1b2c3d4-0000-0000-0000-000000000001",
    "workspace_id": "WORKSPACE_ID",
    "enabled": true,
    "completion_criteria": "first_transaction",
    "distribution_id": "d4c3b2a1-0000-0000-0000-000000000002",
    "pending_expiry_days": 30,
    "max_referrals_per_referrer": 10
  }
}

SDK

typescript
const { data: program } = await wh.referrals.updateProgram(workspaceId, {
  enabled: true,
  completion_criteria: "first_transaction",
  distribution_id: "d4c3b2a1-0000-0000-0000-000000000002",
  pending_expiry_days: 30,
  max_referrals_per_referrer: 10,
});

Delete Referral Program

DELETE /wallethero-api/workspace/:workspaceId/referral-program

Deletes the program and cancels all its pending referrals (kill switch). Completed/expired referral history is preserved. Responds 404 when no program exists.

Auth: Bearer token — workspace member

Response (200)

json
{ "data": { "deleted": true, "cancelled_pending": 4 } }

SDK

typescript
const { data } = await wh.referrals.deleteProgram(workspaceId);

List Referrals

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

Returns a paginated list of referral records for the workspace, enriched with the referrer's and referee's name and email. Supports filtering by status, by referrer/referee client, and free-text search.

Auth: Bearer token — workspace member

Path Parameters

ParameterTypeDescription
workspaceIdstring (UUID)Workspace identifier

Query Parameters

ParameterTypeRequiredDefaultDescription
status"pending" | "completed" | "expired" | "cancelled"NoFilter by referral status
referrer_client_idstring (UUID)NoOnly referrals made by this client
referee_client_idstring (UUID)NoOnly referrals where this client is the referee
searchstringNoCase-insensitive match on referrer/referee name, email, or referral code
limitnumberNo50Max items to return (1–100)
offsetnumberNo0Number of items to skip

Example Request

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

Response (200)

json
{
  "data": [
    {
      "id": "f00d0000-0000-0000-0000-000000000010",
      "workspace_id": "WORKSPACE_ID",
      "referrer_client_id": "c1000000-0000-0000-0000-000000000001",
      "referee_client_id": "c2000000-0000-0000-0000-000000000002",
      "referral_code": "K7P2QX9M",
      "status": "completed",
      "completion_criteria": "first_transaction",
      "qualifying_event_type": "purchase",
      "qualifying_event_id": "e1000000-0000-0000-0000-000000000099",
      "completed_at": "2026-02-12T10:00:00.000Z",
      "cancelled_at": null,
      "expires_at": null,
      "date_created": "2026-02-01T09:00:00.000Z",
      "date_updated": "2026-02-12T10:00:00.000Z",
      "referrer_first_name": "Jane",
      "referrer_last_name": "Doe",
      "referrer_email": "[email protected]",
      "referee_first_name": "John",
      "referee_last_name": "Smith",
      "referee_email": "[email protected]"
    }
  ],
  "meta": { "total": 1, "limit": 25, "offset": 0 }
}

referrer_client_id / referee_client_id are null when the client was deleted (referral history is anonymized, not erased).

SDK

typescript
const result = await wh.referrals.list(workspaceId, {
  status: "completed",
  search: "jane@",
  limit: 25,
});
// result.data, result.meta

Referral Stats

GET /wallethero-api/workspace/:workspaceId/referrals/stats

Returns aggregate referral counts for the workspace, grouped by status.

Auth: Bearer token — workspace member

Example Request

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

Response (200)

json
{
  "data": { "pending": 4, "completed": 12, "expired": 1, "cancelled": 0 }
}

SDK

typescript
const { data: stats } = await wh.referrals.getStats(workspaceId);

Referral Analytics

GET /wallethero-api/workspace/:workspaceId/referrals/analytics

Returns a daily created/completed timeline and the top 10 referrers.

Auth: Bearer token — workspace member

Query Parameters

ParameterTypeRequiredDefaultDescription
daysnumberNo90Window size in days (1–365)

Response (200)

json
{
  "data": {
    "timeline": [
      { "date": "2026-02-01", "created": 3, "completed": 1 },
      { "date": "2026-02-02", "created": 1, "completed": 2 }
    ],
    "top_referrers": [
      {
        "client_id": "c1000000-0000-0000-0000-000000000001",
        "first_name": "Jane",
        "last_name": "Doe",
        "email": "[email protected]",
        "completed_count": 5,
        "pending_count": 2
      }
    ]
  }
}

SDK

typescript
const { data: analytics } = await wh.referrals.getAnalytics(workspaceId, 30);

Cancel a Referral

POST /wallethero-api/workspace/:workspaceId/referrals/:referralId/cancel

Voids one pending referral. Responds 404 for an unknown referral and 409 when the referral is not pending.

Auth: Bearer token — workspace member

Response (200)

json
{ "data": { "id": "f00d0000-0000-0000-0000-000000000010", "status": "cancelled", "cancelled_at": "2026-07-06T12:00:00.000Z" } }

SDK

typescript
const { data: referral } = await wh.referrals.cancel(workspaceId, referralId);

Cancel All Pending Referrals

POST /wallethero-api/workspace/:workspaceId/referrals/cancel-pending

Voids every pending referral in the workspace (kill switch — e.g. after detecting abuse). Returns the number cancelled.

Auth: Bearer token — workspace member

Response (200)

json
{ "data": { "cancelled": 7 } }

SDK

typescript
const { data } = await wh.referrals.cancelAllPending(workspaceId);

Manually Complete a Referral

POST /wallethero-api/workspace/:workspaceId/referrals/:referralId/complete

Admin override: completes a pending referral regardless of program state, referrer cap, or expiry, and publishes the normal referral_completed events (so configured reward automations fire). qualifying_event_type is recorded as "manual". Responds 404 for an unknown referral and 409 when it is not pending.

Auth: Bearer token — workspace member

Response (200)

json
{ "data": { "id": "f00d0000-0000-0000-0000-000000000010", "status": "completed", "qualifying_event_type": "manual" } }

SDK

typescript
const { data: referral } = await wh.referrals.complete(workspaceId, referralId);

Get Client Referral Info

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

Returns one client's referral code, the share link for distributing it, and the client's referral stats. Used to power the per-client referral panel in the dashboard.

A missing code is only minted when the program is enabled and the client is enrolled in the loyalty program — browsing client pages does not create codes as a side effect. Already-assigned codes are always returned.

Auth: Bearer token — workspace member

Path Parameters

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

Example Request

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

Response (200)

json
{
  "data": {
    "code": "K7P2QX9M",
    "share_url": "https://app.wallethero.com/distribution/public/loyalty-signup?ref=K7P2QX9M",
    "stats": { "pending": 2, "completed": 5, "expired": 0, "cancelled": 0 },
    "program_enabled": true
  }
}

code is null when the client has no code yet and it cannot be minted (program disabled/missing, or client not loyalty-enrolled). share_url is null when there is no code or the referral program has no distribution_id configured (or the distribution has no public page address).

SDK

typescript
const { data: info } = await wh.referrals.getClientReferral(workspaceId, clientId);

WalletHero Documentation