listOffers returns
the offers available to the calling member, each with its points price and
optional expiry, paged with a cursor.
Reading the catalog works with either credential.
GET /v1/offers and
GET /v1/offers/{id} accept your Org-API-Key directly or a member token, so your
backend can browse the catalog without minting one. Setting a price is
server-side only - PUT/DELETE /v1/offers/{id}/price require the Org-API-Key
with config:write and reject a member token.See Authentication. Whether you read the sandbox demo catalog
or your live catalog is selected by the key - see Environments.List offers
listOffers(limit?, cursor?) calls GET /v1/offers and returns an OfferList.
The snippet below pages through the entire catalog by following nextCursor
until it comes back null:
curl
The Offer schema
Each entry indata is an Offer:
Every field added above is nullable except
availability and inclusions.
No experience carries all of them - build for null on each.
description is unchanged and still contains the full editorial copy,
including prose forms of what is now structured. Render the structured fields
and use description for the narrative paragraph.Prices in your own currency
display carries the price in your members’ currency, so you never have to do the
arithmetic or explain a points figure:
display.amount and render it with display.currency.symbol. Read
unitsPerUSD from the response rather than hardcoding it - you can change it
yourself at any time, and a hardcoded copy would silently disagree with the API
the moment you did. See
Currency configuration.
display.source tells you where the number came from:
amount is a number, not an integer. If a credit is worth $1,000 and an
experience is $1,650, the answer is 1.65 - and rounding that to a whole credit
would move real money between what you charge your member and what you pay us.
Nothing is rounded: a derived price is exact, and an authored price is returned
exactly as you set it, including 39.5.This changed in 0.5.0. If you are on the Kotlin or Swift SDK, amount and the
wallet *Display fields moved from Int to Double - upgrade before you take the
new server behaviour. TypeScript and raw HTTP need no change.Setting your own price per experience
A single ratio makes every price a mechanical function of our cost. When you want to price a $75,000 experience differently from a $2,000 one, author the price yourself:config:write scope, and both are server-to-server only.
Availability and sold-out experiences
Every offer carries anavailability object:
isAvailable is not simply quantityRemaining > 0: an experience with no points
price also cannot be redeemed, so it reports false while quantityRemaining
stays truthful. Branch on isAvailable, not on the count.
The default list still includes sold-out experiences. That is deliberate - a
card that greys out reads better than one that vanishes between two nightly cache
loads. To hide them, opt in:
curl
Read a single offer
GET /v1/offers/{id} returns exactly the shape the list returns for that offer -
one serializer, so the two cannot drift. Use it for deep links.
curl
404
with the standard error envelope. The two responses are identical: the platform
does not confirm whether another tenant’s offer exists.
pointsPrice is your price, not a catalogue-wide one. Two accounts can see a
different pointsPrice for the same id: we price each experience for each account
from its cost and your commercial terms, rounded to your agreed points increment.
The value returned is always exactly what a redemption of that offer will debit you,
and display.amount is derived from it. The field, its type and its meaning are
unchanged; if your commercial terms change, we tell you before any price moves.pointsPrice of null is distinct from 0: it means the offer carries no
points price at all. An offer past its expiresAt is no longer redeemable -
attempting to redeem it returns OFFER_UNAVAILABLE. See
Redemptions.Pagination
OfferList is cursor-paginated:
Pagination is cursor-based, not page-numbered. Pass the previous response’s
nextCursor as the next request’s cursor, and stop when nextCursor is
null. Do not assume a fixed page size or construct cursors yourself - treat
the cursor as an opaque token.Next steps
Redemptions
Redeem an offer, spend points, and follow the redemption lifecycle.
Points and wallet
How points are minted, spent, and tracked against
pointsPrice.API reference
The full
GET /v1/offers schema and an interactive playground.