Use these REST endpoints when you want the same data as the Points History widget without embedding the iframe or web component. The ledger payload matches the fields the widget renders.
Open the live OpenAPI UI and jump to each operation:
| Endpoint | Redoc |
|---|---|
GET /api/widget/points-history | /api/docs#operation/getPointsHistory |
GET /api/widget/claim-rewards/balance | /api/docs#operation/getPointsBalance |
| Full Widget tag | /api/docs#tag/Widget |
| Machine-readable spec | /api/docs/spec |
clientId + clientSecret) with your origins registered —
see SSO.PIONEER_WIDGETS=1. When the
flag is off, these routes return 404.https://app.yourshop.com), referred to below as
{BASE_URL}.Send an SSO (or hub) bearer token:
Authorization: Bearer {TOKEN}Mint the token server-to-server via POST /api/auth/sso (never expose
clientSecret in the browser), or use window.legionAuth.getToken() when the
storefront runs the Legion SSO WordPress plugin. Middleware verifies the JWT
and stamps x-user-id for the handlers — clients only need the
Authorization header.
CORS is granted for origins registered on your SSO client.
GET {BASE_URL}/api/widget/claim-rewards/balance
Authorization: Bearer {TOKEN}1{
2 "balance": 1500,
3 "currency": "points",
4 "asOf": "2026-06-15T22:14:03.000Z"
5}Use this for a balance badge above your history table. Swagger: getPointsBalance.
GET {BASE_URL}/api/widget/points-history?limit=10&offset=0
Authorization: Bearer {TOKEN}| Query | Default | Notes |
|---|---|---|
limit | 10 | Max 100 |
offset | 0 | Skip N rows for pagination |
1{
2 "data": [
3 {
4 "id": "b1c2d3e4-…",
5 "amount": 150,
6 "balance": 1500,
7 "transaction_type": "earn",
8 "description": "Order #1042",
9 "reference_type": "order",
10 "created_at": "2026-06-15T22:14:03.000Z"
11 }
12 ],
13 "pagination": { "limit": 10, "offset": 0, "total": 87 }
14}Rows are newest-first and scoped to the authenticated shopper on the current shop. Swagger: getPointsHistory.
| Field | Typical UI use |
|---|---|
created_at | Date / time column |
description or transaction_type | Label (prefer description when present) |
amount | Signed points delta (+150 / -50) |
balance | Running balance after the row |
transaction_type | Badge / filter (earn, claim, redeem, …) |
reference_type | Optional secondary label (order, point_claim, …) |
pagination.total | Page count / “Showing X–Y of Z” |
Common transaction_type values: earn, claim, redeem, adjustment,
refund, reversal. When the type is claim, reference_type is usually
point_claim.
1async function loadPointsHistory(
2 baseUrl,
3 token,
4 { limit = 10, offset = 0 } = {}
5) {
6 const url = new URL("/api/widget/points-history", baseUrl);
7 url.searchParams.set("limit", String(limit));
8 url.searchParams.set("offset", String(offset));
9
10 const res = await fetch(url, {
11 headers: { Authorization: `Bearer ${token}` },
12 });
13
14 if (!res.ok) {
15 throw new Error(`points-history failed: ${res.status}`);
16 }
17
18 return res.json(); // { data, pagination }
19}
20
21// Example: first page
22const { data, pagination } = await loadPointsHistory(
23 "https://app.yourshop.com",
24 token,
25 { limit: 10, offset: 0 }
26);Fetch the next page with offset = pagination.offset + pagination.limit while
offset < pagination.total.
On shops that hold earnings as reservations until the shopper claims them:
GET /api/user/points/claimablePOST /api/user/points/claimclaim row appears in the ledgerFull walkthrough: Point Reservations guide.
If you prefer the packaged UI (table, theming, pagination):