← Trivu

API and webhooks

Connect your register, your online store or any system of your own to Trivu Loyalty. Available on the Business plan and on Agency Scale clients.

Authentication

Create keys in Settings → API and webhooks (owners and admins only). Send the key in every request:

Authorization: Bearer tlk_xxxxxxxxxxxxxxxxxxxxxxxx

Base URL: https://loyalty.trivuapp.com/api/v1. Errors look like {"error":"CODE"} with the matching HTTP status.

Endpoints

GET/membersList members (search, limit, cursor)
GET/members/{id}One member with cards and balances
POST/membersCreate a member (write key)
POST/transactionsEarn or spend balance (write key)
POST/redemptionsRedeem a reward (write key)
GET/programsActive programs and their rewards

Adding balance

curl https://loyalty.trivuapp.com/api/v1/transactions \
  -H "Authorization: Bearer tlk_xxxxxxxx" \
  -H "Content-Type: application/json" \
  -d '{
    "passId": "cmv...",
    "unit": "POINTS",
    "kind": "EARN",
    "amount": 40,
    "spendCents": 1250,
    "reason": "Compra en caja",
    "idempotencyKey": "venta-10482"
  }'

idempotencyKey (8 to 150 characters) is required: repeating the same request with the same key never adds twice, it returns the original movement. Use a stable id from your sale. The answer includes the resulting balance; 409 INSUFFICIENT_BALANCE if the balance is not enough.

Webhooks

A webhook is a public https address of your system that Trivu calls when something happens. Up to 5 per business; private or internal addresses are not accepted.

member.createdA member card is created (dashboard, sign-up page or API)
transaction.createdAny points, stamps or cashback movement, including birthday and automation bonuses. Gift cards do not emit events yet
reward.redeemedA reward is redeemed (also emits transaction.created)

Events carry ids and the movement, not personal data: use GET /members/{id} to look the person up.

{
  "id": "cmv...",
  "type": "transaction.created",
  "createdAt": "2026-11-02T15:04:05.000Z",
  "data": {
    "entryId": "cmv...",
    "passId": "cmv...",
    "customerId": "cmv...",
    "unit": "POINTS",
    "kind": "EARN",
    "amount": 40,
    "reason": "Compra en caja",
    "branchId": null,
    "createdAt": "2026-11-02T15:04:05.000Z"
  }
}

Verify the signature

Each delivery has the headers Trivu-Event, Trivu-Delivery (same as the event id: use it to ignore duplicates) and Trivu-Signature, in the form t=<seconds>,v1=<hex>. v1 is the HMAC-SHA256 of "<t>.<exact body received>" with the webhook's secret (whsec_…, shown once). Reject events with a wrong signature or an old t.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verify(secret, header, rawBody) {
  const [t, v1] = header.split(",").map((p) => p.split("=")[1]);
  if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false;
  const expected = createHmac("sha256", secret)
    .update(`${t}.${rawBody}`)
    .digest("hex");
  return v1.length === expected.length &&
    timingSafeEqual(Buffer.from(v1), Buffer.from(expected));
}

Delivery and retries