pointsPrice from the member’s wallet; canceling one refunds those points.
This guide covers creating, fetching, and listing redemptions.
These work with either credential. Creating and reading redemptions accepts your
Org-API-Key directly or a member token - a server-side integration can book on a
member’s behalf by naming them with
externalUserID, without minting a token.See Authentication. Whether the redemption lands in sandbox or
live is selected by the key - see Environments.Create a redemption
createRedemption(input, options/idempotencyKey?) calls
POST /v1/redemptions and returns 201 with the created Redemption. The body
is a CreateRedemptionRequest:
Redeeming debits the offer’s
pointsPrice from the member’s balance. If the
balance is below the price, the call fails with INSUFFICIENT_POINTS rather than
going negative.
curl
Safe retries with an idempotency key
Because creating a redemption spends points, always send anIdempotency-Key
header (the SDK accepts it via idempotencyKey). If a network blip makes you
retry, the server returns the original redemption instead of charging twice.
Reusing a key with a different body is rejected with IDEMPOTENCY_KEY_REUSED.
Fetch a redemption
getRedemption(id) calls GET /v1/redemptions/{id} and returns a single
Redemption:
Cancellations
A booking can be canceled after it is created - a vendor releases inventory, a date falls through, a member asks. Both fields are present on every redemption,null for anything not canceled, so you never have to check the
status before reading them.
canceledReason is one of:
canceledNote is member-facing. It is written by the operator handling the
booking specifically so you can show it, and it is capped at one line. It is not
an internal note.redemption.canceled webhook with the same values -
see Webhooks. Points are refunded automatically on cancel,
to whichever layer paid for the redemption; nothing is required from you.
Sold-out experiences
Redeeming a sold-out experience fails immediately and synchronously:422 OFFER_UNAVAILABLE, no booking created, no points debited. It never succeeds
and then comes back canceled later.
Inventory is held from the moment of redemption, not from the moment we confirm
the booking, so two members cannot both claim the last unit. The practical
consequence is that OFFER_UNAVAILABLE now also covers “the last unit is held by
another member’s in-flight redemption”, not only “this never had stock”.
A member can redeem a given experience once, and a canceled redemption
still holds that slot. If a member should be able to book the same thing twice,
that needs to be two entries in the catalog.
curl
List redemptions
listRedemptions(...) calls GET /v1/redemptions and returns a
ListRedemptionsResponse with redemptions and a nextCursor. It accepts
limit, cursor, externalUserID, and a status filter. The snippet below
pages through a member’s OPEN redemptions:
ListRedemptionsResponse is cursor-paginated: follow nextCursor until it is
null. Treat the cursor as an opaque token.Status lifecycle
A redemption moves through these statuses as the experience is booked and fulfilled:Canceling a redemption refunds the debited points back to the member’s
wallet. See Points and wallet for how the balance
reflects debits and refunds.
Errors
Branch on the errorcode, never on message. The redemption-specific codes
are:
See Errors for the full taxonomy, the shared error shape, and
the
requestId you quote to support.
Next steps
Points and wallet
How debits and refunds move the member’s balance.
Retries and idempotency
The idempotency-key contract and automatic retry behavior.
Errors
Stable codes, the error shape, and the request id.
Post-experience feedback
Once an experience iscompleted, the member can score it. Zero to ten, the NPS scale,
with an optional comment.
feedback:
object | null
required
{ rating, comment, submittedAt }, or null until the member scores it.Only a
completed redemption accepts feedback. Anything else is refused with
REDEMPTION_NOT_COMPLETED, and the error names the current status so you can say
something useful - a booking awaiting a vendor and one that was cancelled need very
different words, and only you know how to say them.Submitting again replaces the previous answer. People revise.GET /v1/analytics/offers as
averageRating and ratingCount. averageRating is null, never 0, when nobody
has rated - zero is a real score, and an unrated experience must not sort alongside a
hated one.