Loyalty activity

GET /loyalty-activity

List loyalty activity, newest first. Every entry is part of the append-only ledger: points earns, spends, manual adjustments, revocations and expiries. Supports search, filtering and cursor pagination.

Requires the loyalty:read permission.

Query Parameters

limitnumber

The number of records to return.

cursorstring

A pagination cursor. Fetch the next page by passing the nextCursor value from the previous response.

sortcreatedAt | -createdAt | amount | -amount

The sort order. Prefix a field with - to sort descending. Defaults to -createdAt.

searchstring

A free-text search term, matched case-insensitively against the record's most identifying fields. Combined with filter using AND.

filterstring

A JSON-encoded filter document, for example {"createdAt":{"$gte":"2025-01-01T00:00:00Z"}}. Filterable fields: id, type, loyaltyMembershipId, amount, revokeTransactionId, createdAt, customer.id, customer.email, customer.firstName, customer.lastName, customer.metadata, customer.emailOptOut, customer.emailOptOutSource, customer.createdAt, rule.id, rule.name. See Filtering for the syntax.

includestring

A comma-separated list of extra fields to compute and return. Each one costs an additional query, so ask only for what you need. Available: customer, rule, membership.

Request
curl \
  "https://api.cascade.dev/loyalty-activity" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "data": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "type": "points",
      "loyaltyMembershipId": "550e8400-e29b-41d4-a716-446655440000",
      "loyaltyRuleId": "550e8400-e29b-41d4-a716-446655440000",
      "amount": 0,
      "balanceAfter": 0,
      "details": "...",
      "revokeTransactionId": "550e8400-e29b-41d4-a716-446655440000",
      "eventKey": "string",
      "createdAt": "2025-01-15T09:30:00Z",
      "updatedAt": "2025-01-15T09:30:00Z",
      "customer": {
        "id": "...",
        "email": "...",
        "phone": "...",
        "firstName": "...",
        "lastName": "...",
        "country": "...",
        "birthday": "...",
        "metadata": "...",
        "notes": "...",
        "emailOptOut": "...",
        "emailOptOutAt": "...",
        "emailOptOutSource": "...",
        "createdAt": "...",
        "updatedAt": "..."
      },
      "rule": {
        "id": "...",
        "name": "...",
        "section": "..."
      },
      "membership": {
        "id": "...",
        "customerId": "...",
        "loyaltyProgramId": "...",
        "loyaltyTierId": "...",
        "tierAssignedManually": "...",
        "tierAttainedAt": "...",
        "tierReviewAt": "...",
        "leftAt": "...",
        "referralCode": "...",
        "createdAt": "...",
        "updatedAt": "..."
      }
    }
  ],
  "nextCursor": "string"
}

POST /loyalty-activity/adjustments

Manually adjust a member's points balance, up or down, with a required reason stored on the entry. A deduction may push the balance below zero, for example when correcting fraud. Triggers the loyaltyTransaction.created webhook.

Requires the loyalty:write permission.

Body Parameters

dataobjectrequired

The adjustment to apply.

Request
curl \
  -X POST \
  "https://api.cascade.dev/loyalty-activity/adjustments" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY" \
  -H "Content-Type: application/json" \
  -d '{
  "data": {
    "loyaltyMembershipId": "550e8400-e29b-41d4-a716-446655440000",
    "amount": 0,
    "reason": "string"
  }
}'
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "points",
  "loyaltyMembershipId": "550e8400-e29b-41d4-a716-446655440000",
  "loyaltyRuleId": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 0,
  "balanceAfter": 0,
  "details": "...",
  "revokeTransactionId": "550e8400-e29b-41d4-a716-446655440000",
  "eventKey": "string",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "customer": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "phone": "string",
    "firstName": "string",
    "lastName": "string",
    "country": "string",
    "birthday": "string",
    "metadata": "...",
    "notes": "string",
    "emailOptOut": true,
    "emailOptOutAt": "2025-01-15T09:30:00Z",
    "emailOptOutSource": "customer",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  },
  "rule": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "string",
    "section": "rules"
  },
  "membership": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "customerId": "550e8400-e29b-41d4-a716-446655440000",
    "loyaltyProgramId": "550e8400-e29b-41d4-a716-446655440000",
    "loyaltyTierId": "550e8400-e29b-41d4-a716-446655440000",
    "tierAssignedManually": true,
    "tierAttainedAt": "2025-01-15T09:30:00Z",
    "tierReviewAt": "2025-01-15T09:30:00Z",
    "leftAt": "2025-01-15T09:30:00Z",
    "referralCode": "string",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  }
}

POST /loyalty-activity/bulk-expire

Expire outstanding points in bulk, for example everything earned in a retired currency or before a cutoff date. For each member and currency with matching earns, an offsetting expiry transaction is appended so the balance math stays intact, clamped so no balance goes below zero. Omitting the filter considers every transaction in the organization.

Requires the loyalty:write permission.

Costs 5 rate limit tokens instead of the usual one. See Rate limits.

Query Parameters

filterstring

A JSON-encoded filter document selecting the transactions to expire, for example points earned before a cutoff date. Omit it and every transaction in the organization is considered. See Filtering for the syntax.

Request
curl \
  -X POST \
  "https://api.cascade.dev/loyalty-activity/bulk-expire" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "count": 0,
  "amountExpired": 0
}

POST /loyalty-activity/{id}/revoke

Reverse a points entry by appending a compensating entry of the opposite amount, linked through revokeTransactionId. Only points entries that are not themselves revocations and have not already been revoked can be revoked; anything else returns a 409. Revoking an earn the member already spent may push the balance below zero. Triggers the loyaltyTransaction.created webhook.

Requires the loyalty:write permission.

Path Parameters

idstring (uuid)required

The ID of the points entry to revoke.

Request
curl \
  -X POST \
  "https://api.cascade.dev/loyalty-activity/550e8400-e29b-41d4-a716-446655440000/revoke" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "points",
  "loyaltyMembershipId": "550e8400-e29b-41d4-a716-446655440000",
  "loyaltyRuleId": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 0,
  "balanceAfter": 0,
  "details": "...",
  "revokeTransactionId": "550e8400-e29b-41d4-a716-446655440000",
  "eventKey": "string",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "customer": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "phone": "string",
    "firstName": "string",
    "lastName": "string",
    "country": "string",
    "birthday": "string",
    "metadata": "...",
    "notes": "string",
    "emailOptOut": true,
    "emailOptOutAt": "2025-01-15T09:30:00Z",
    "emailOptOutSource": "customer",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  },
  "rule": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "string",
    "section": "rules"
  },
  "membership": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "customerId": "550e8400-e29b-41d4-a716-446655440000",
    "loyaltyProgramId": "550e8400-e29b-41d4-a716-446655440000",
    "loyaltyTierId": "550e8400-e29b-41d4-a716-446655440000",
    "tierAssignedManually": true,
    "tierAttainedAt": "2025-01-15T09:30:00Z",
    "tierReviewAt": "2025-01-15T09:30:00Z",
    "leftAt": "2025-01-15T09:30:00Z",
    "referralCode": "string",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  }
}

GET /loyalty-activity/{id}

Get a single loyalty activity entry by ID.

Requires the loyalty:read permission.

Path Parameters

idstring (uuid)required

The ID of the activity entry.

Query Parameters

includestring

A comma-separated list of extra fields to compute and return. Each one costs an additional query, so ask only for what you need. Available: customer, rule, membership.

Request
curl \
  "https://api.cascade.dev/loyalty-activity/550e8400-e29b-41d4-a716-446655440000" \
  -H "Authorization: Bearer sk_YOUR_SECRET_KEY"
Response
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "type": "points",
  "loyaltyMembershipId": "550e8400-e29b-41d4-a716-446655440000",
  "loyaltyRuleId": "550e8400-e29b-41d4-a716-446655440000",
  "amount": 0,
  "balanceAfter": 0,
  "details": "...",
  "revokeTransactionId": "550e8400-e29b-41d4-a716-446655440000",
  "eventKey": "string",
  "createdAt": "2025-01-15T09:30:00Z",
  "updatedAt": "2025-01-15T09:30:00Z",
  "customer": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "email": "[email protected]",
    "phone": "string",
    "firstName": "string",
    "lastName": "string",
    "country": "string",
    "birthday": "string",
    "metadata": "...",
    "notes": "string",
    "emailOptOut": true,
    "emailOptOutAt": "2025-01-15T09:30:00Z",
    "emailOptOutSource": "customer",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  },
  "rule": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "name": "string",
    "section": "rules"
  },
  "membership": {
    "id": "550e8400-e29b-41d4-a716-446655440000",
    "customerId": "550e8400-e29b-41d4-a716-446655440000",
    "loyaltyProgramId": "550e8400-e29b-41d4-a716-446655440000",
    "loyaltyTierId": "550e8400-e29b-41d4-a716-446655440000",
    "tierAssignedManually": true,
    "tierAttainedAt": "2025-01-15T09:30:00Z",
    "tierReviewAt": "2025-01-15T09:30:00Z",
    "leftAt": "2025-01-15T09:30:00Z",
    "referralCode": "string",
    "createdAt": "2025-01-15T09:30:00Z",
    "updatedAt": "2025-01-15T09:30:00Z"
  }
}