Redeem points at checkout
Use this when a customer pays with points rather than a voucher. It has the same shape as a paid voucher claim: your server reserves, and the customer signs.
1. Reserve on your server
Section titled “1. Reserve on your server”pointsAmount here means real points.
const reservation = await client.reservePosRedemption({ organizationEndUserId: memberId, pointsAmount: 500, idempotencyKey: `pos-${order.id}`,});Send digest and transactionBytes to the customer’s device. If the same key already settled, both are null and status tells you the result.
The member needs enough available points, a linked Sui address and an on-chain account, which their first earn creates. Otherwise you get a 400.
2. Sign on the customer’s device
Section titled “2. Sign on the customer’s device”const signature = await auth.signTransaction(reservation.transactionBytes);signTransaction refuses bytes whose sender isn’t the signed-in customer, with the code wrong-account.
3. Finalize
Section titled “3. Finalize”Send the signature to your server, and finalize there or from the customer’s device. The signature authorizes this, not your API key.
const result = await client.finalizePosRedemption({ digest: reservation.digest, signature,});// result.pointsRedeemed, result.newBalance, result.blockchainDigestUse these two calls here. auth.signAndFinalize only accepts a voucher claim, because it requires status: 'RESERVED', and a reservation’s status is PENDING.
If something goes wrong
Section titled “If something goes wrong”| What you see | What to do |
|---|---|
| 404 on finalize | The reservation expired, or it already finalized. Read history before you reserve again. |
| 409 on finalize | It was released or another digest is in progress. Read history first. |
| 400 on finalize | It may have failed on-chain or after sending. Read history before you retry. |
| Timeout or 5xx | Unknown outcome. Read history, or reserve again with the same key. |
A hold that is never signed is released after 30 minutes.

