Skip to content
Loyalty Pilot

The loyalty engine behind your product.

Points, tiers and rewards over one API. Your customers see your brand. You see every point.

Illustration, showing 6 example businesses in turn. Now showing: Online shop. On a customer's phone, the Halden Coffee app takes a $52.40 order. The app calls the Loyalty Pilot earning endpoint, which awards 52 points: the balance moves from 1226 to 1278 and the customer reaches Gold, with new perks. At the same moment the merchant's console shows the points issued, the new Gold member and a level.changed webhook delivered.

Wherever your customers pay.

Online, in an app, at the till or across a marketplace. If it can make an HTTP call, it can award points.

How it works

From sign-up to first points in an afternoon.

  1. Create an application

    One per integration: your web shop, your app, your tills. Each keeps its own customers and points, in Test or Live.

    New application

    EnvironmentTestLive
    Halden web shopTest · its own customers and pointsActive
  2. Take your credentials

    OAuth 2.0 client credentials. Exchange them for a token that can only ever reach that application.

    Credentials

    Client IDloyalty-app-01JX8T3M2Q7V
    Client secret••••••••••••••••••••

    Shown once. Store it in your secret manager.

    POST $IDENTITY_URL/connect/token
    grant_type=client_credentials
    scope=loyalty.api
  3. Send events

    Call the earning endpoint, or map events you already emit to rules. Caps, cooldowns and tiers apply on their own.

    Award points

    POST /api/v1/Engine/Earning
    {
      "externalCustomerId": "CUST-20417",
      "ruleCode": "PURCHASE",
      "amount": 52.40,
      "idempotencyKey": "order-40912"
    }

    200pointsChanged 52, newBalance 1278

    Or map events you already send

    order.completed to rule PURCHASE

  4. Watch it work

    Members, points issued, redemptions and every webhook that failed, for each application.

    Halden web shop

    Example data
    Members
    3,912
    Points issued
    18,458
    Redemptions
    214
    • CUST-20417Earned 52 pointsjust now
    • CUST-18862Redeemed Free drink2 min ago
    • CUST-20417Reached Goldjust now

The parts that take months to build, already built.

Earning rules you configure, not code

Fixed, percentage or banded awards, with daily, weekly, monthly and lifetime caps and cooldowns.

PURCHASE

1 point for every $1 spent

  • Up to 500 points a day
  • 2,000 a week
  • 10 minute cooldown
  • Lifetime cap off
Today, for CUST-20417380 of 500

Tiers that manage themselves

Members move up and down on every transaction, and the perks follow them.

  1. Platinum2,500+
  2. Gold1,250+
  3. Silver500+
  4. Bronze0+

A catalogue priced in points

Customers see what they can afford right now.

  • Free drink400 pointsRedeem
  • Bag of beans1,100 pointsRedeem
  • Brewing class3,000 points1,722 to go

A ledger finance can reconcile

Every movement, with the balance after it and your own key.

ChangeBalance afterIdempotency key
+521,278order-40912
-4001,226redeem-7781
+1181,626order-40388

Webhooks you can verify

Balance, tier and redemption events, each signed with HMAC-SHA256.

POST /hooks/loyalty

X-Loyalty-Signature: sha256=9f2c41e07b…

{ "event": "level.changed", "level": "Gold" }

Signature verified

Or send the events you already have

Map your own event names to rules and let the engine decide what each one earns.

  • order.completedPURCHASE
  • review.postedREVIEW
  • referral.convertedREFERRAL

Every application is its own vault.

One account, many applications. Isolation is enforced in the data layer on every query, so a token for your web shop can never read your tills.

  • Separate customers, balances and ledger
  • Separate OAuth credentials for each application
  • Test and Live never share data

One call to award. The same call to retry.

REST, gRPC or the .NET SDK. Send an idempotency key with every award and a retried request can never pay out twice.

curl -X POST "$LOYALTY_API/api/v1/Engine/Earning" \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "externalCustomerId": "CUST-20417",
    "ruleCode": "PURCHASE",
    "amount": 52.40,
    "idempotencyKey": "order-40912"
  }'

200Response

{
  "success": true,
  "result": {
    "transactionId": "01JXB2K7…",
    "pointsChanged": 52,
    "newBalance": 1278,
    "success": true
  }
}

See whether it is working.

Every application has its own dashboard: who joined, what was earned, what was redeemed, and why something was not awarded.

Web shop

Live application

Example data
Members
3,912
+148 this week
Points issued
184,206
last 30 days
Redemptions
1,027
last 30 days
Failed webhooks
0
last 24 hours
Points issued, last 14 days

Recent activity

  • Earned 52 pointsCUST-20417 PURCHASE
  • Reached GoldCUST-20417 level.changed
  • Redeemed Free drinkCUST-18862 400 points
  • Not awarded: daily cap reachedCUST-31190 PURCHASE

Points are a liability. We treat them like one.

How we protect your data

Launch your pilot programme.

Start with a Test application and your own data. Go Live when you are ready.