Every field name in the API comes from a small set of ideas. Read this once and the reference will make sense.
Money and points are integers
Everything is an integer in minor units: paise for INR, cents for USD. gross_cents: 249900 is ₹2,499.00. Points are the same — a programme where 1 point is worth ₹1 stores 1 point as 100. The programme's currency_name ("VibeCoins", "Stars") is what members see; the API never rounds and never uses floats.
A member
One person in one programme, identified by email (the anchor — it never changes through the API), optionally a phone and your own external_ref. Anywhere the API takes a member id you may send our M-… id, ref:<your id> or phone:<number>. A member has a state: prospect (seen on an order, has not agreed to terms), registered, active, paused, suspended, deleted, anonymised.
The ledger and the four balances
Points live in an append-only ledger: earns, adjustments, redemptions, reversals, expiries. Nothing is ever edited; corrections are new entries. From it we keep four numbers per member:
| Balance | Meaning |
|---|---|
pending_cents | Earned, not yet usable — waiting for a return window or a manual approval. |
available_cents | Usable now. |
reserved_cents | Held by an open checkout reservation. |
spendable_cents | available − reserved: what a redemption may take right now. Use this one. |
lifetime_earned_cents and lifetime_redeemed_cents are running totals.
Earning
An order.paid (or order.placed / order.fulfilled, depending on the programme's timing) runs the programme's rules — base rate, tier rate, category boosts, campaigns, caps and budgets — and writes earn entries. Whether they land pending or available is the programme's release timing (immediately, on payment, on fulfilment, after the return window). order.refunded and order.cancelled write the reversal.
Tiers
Levels a member holds by meeting a threshold (spend or orders) over a window (rolling 365 days, calendar year, lifetime). A tier can change the earn rate and unlock benefits your storefront may read. Tier is evaluated by the programme, not set through the API.
Redeeming: reservations and vouchers
Two ways to spend, both take the row lock so a balance can never go negative by a race:
- Reservation (custom checkout):
quote→reserve(holds points, 15 min) →confirmwith anorder_ref, orrelease. Points are only debited on confirm. - Voucher (till, phone order):
POST /v1/members/{id}/redemptionsdebits immediately and returns a single-use code; confirm it when it is used, void it to return the points; unconfirmed vouchers return their points on expiry.
Expiry and holds
Points can expire under the programme's policy (fixed days, end of period, inactivity). expiring_30d_cents on a member tells you what is about to. A hold is a reservation's grip on points; under review is an earn waiting for a person to approve it.
Events are asynchronous
POST /v1/events answers 202 and processes in the background, usually within a second. Every event has a status you can read (queued → running → completed / failed) and an error that says why it failed or why it was ignored (an older aggregate_version, a customer nobody could match). Webhooks tell you when balances change.
Conventions
- Timestamps are ISO 8601 in UTC:
2026-09-22T10:31:00.000Z. - Member ids are the stable public form
M-…; internal identifiers never appear. - Lists return
{ data, pagination: { cursor } }. Pass?cursor=for the next page;nullmeans the end. Cursors are stable across inserts, so a walk never skips or repeats a row. - Errors are RFC 9457
application/problem+json— see Errors. - Responses only gain fields inside
/v1— see Versioning.