LoyaltyCheckout reservations
Loyalty
Checkout reservations
Hold part of a balance during checkout.
A checkout reservation holds part of a customer's balance while a payment is pending, without spending it. Confirm it when the payment goes through, release it when it does not, or let it expire. A held balance cannot be spent at the counter meanwhile (409 BENEFIT_RESERVED).
Programs and gift cards can be reserved. Offers, generic passes, event tickets, boarding passes and transit passes are used once, so their reservation routes always answer 422 UNSUPPORTED_ACTION.
Paths are relative to https://app.revisit.cards/v1/developer.
Endpoints
- POSTHold a benefit during checkout without spending it
/programs/{id}/reservations - POSTHold part of a gift card's balance during checkout
/gift-cards/{id}/reservations - POSTNot supported - an offer cannot be reserved
/offers/{id}/reservations - POSTNot supported - a generic pass cannot be reserved
/generic-passes/{id}/reservations - POSTNot supported - an event ticket cannot be reserved
/event-tickets/{id}/reservations - POSTNot supported - a boarding pass cannot be reserved
/boarding-passes/{id}/reservations - POSTNot supported - a transit pass cannot be reserved
/transit-passes/{id}/reservations - GETList this application's reservations, newest first
/reservations - GETRead one reservation
/reservations/{id} - POSTSpend a held benefit after the checkout succeeded
/reservations/{id}/confirm - POSTFree a held benefit after a failed or abandoned checkout
/reservations/{id}/release
Hold a benefit during checkout without spending it
/programs/{id}/reservationsScopeloyalty:write
Requires loyalty:write and an Idempotency-Key. Holds part of one customer's balance while a payment is pending: a Stamp program holds its reward's stamps, a Points (or Points and tiers) program the named reward's points, a Subscription program one included use, a Cashback or Prepaid program amount of its balance (minor units, currency the program's, never converted). The balance does not move; what the customer can spend is the balance less active holds (available), and the counter, actions and a void all leave active holds funded (409 BENEFIT_RESERVED). Concurrent holds queue on the membership: they can never over-commit it (409 INSUFFICIENT_AVAILABLE when other holds are what is in the way, otherwise the card's own refusal code). reference is your checkout or order id and makes the hold happen once under any key; the same reference for something else is 409 SOURCE_EVENT_CONFLICT. The hold lasts expiresInSeconds (60 to 86,400), default 15 minutes (DEVELOPER_RESERVATION_TTL_SECONDS). A Tiered program has nothing to hold (422 UNSUPPORTED_ACTION).
Send an Idempotency-Key header. Safe to retry.
Path
iduuidRequired
Body
externalCustomerIdstringRequiredreferencestringRequired- Your checkout or order id; makes the hold happen once.
branchIduuidrewardIdstring- Points programs.
rewardNamestring- Points programs, by exact name.
amountinteger- Cashback and Prepaid, minor units of the program's currency.
currencyenum- ISO 4217. Fixed per program once money has moved. Minor-unit digits are 0 for JPY, KRW and VND, 3 for BHD, JOD, KWD and OMR, else 2. One of
AED,BDT,BHD,EUR,GBP,INR,JOD,JPY,KRW,KWD,MYR,OMR,SGD,USD,VND. expiresInSecondsinteger- Default 900 (15 minutes). 60 to 86400.
Returns 201
reservationIdstringRequiredstateenumRequired- Read from the clock. One of
active,confirmed,released,expired. amountintegerRequired- Balance units held.
balanceintegerRequired- The membership's balance now; a hold never moves it.
reservedintegerRequired- Held by every active hold on the membership now.
availableintegerRequired- balance less reserved, never below zero.
balanceAfterinteger or nullRequiredcurrencystring or nullRequiredcustomerIdstring or nullRequired- Null for a gift card with no customer.
externalCustomerIdstringRequiredgiftCardIdstring or nullRequired- Set when the hold is on a gift card; then programId and membershipId are null.
membershipIdstring or nullRequiredprogramIdstring or nullRequiredreferencestringRequiredrewardNamestring or nullRequiredtransactionIdstring or nullRequired- The ledger row of the confirmed spend (the counter's pass event for a gift card).
createdAtstringRequiredexpiresAtstringRequireddecidedAtstring or nullRequiredduplicatebooleanRequired
Errors
- 409
BENEFIT_RESERVEDpart of the balance is held by a checkout reservation, so a counter or API spend would leave a hold unfunded. Nothing changed; confirm or release the hold, or let it expire. - 409
INSUFFICIENT_AVAILABLEnot enough is available (the balance less active holds) to hold or spend this. Nothing changed. - 409
SOURCE_EVENT_CONFLICTthis source event id was already applied with different content (another customer, program, action or amount). Nothing changed. - 422
UNSUPPORTED_ACTIONthe action is not one a service may take (top-up, spend, set or adjust a balance, void) or the program's card type does not take earning and redeeming from the API yet. Nothing changed.
curl -X POST "https://app.revisit.cards/v1/developer/programs/e01b010d-2c65-48e1-83a0-acad79f8d3b4/reservations" \
-H "Authorization: Bearer $DEVELOPER_API_KEY" \
-H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8e67f78c" \
-H "Content-Type: application/json" \
-d '{
"externalCustomerId": "user-42",
"reference": "order-2041"
}'{
"data": {
"amount": 1250,
"available": 7,
"balance": 7,
"balanceAfter": 7,
"createdAt": "2026-11-03T08:41:12.000Z",
"currency": "BDT",
"customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
"decidedAt": "2026-11-03T08:41:12.000Z",
"duplicate": false,
"expiresAt": "2026-11-03T08:41:12.000Z",
"externalCustomerId": "user-42",
"giftCardId": "9c83a2c5-ee43-4698-bd57-cbed81fdc409",
"membershipId": "b53ca741-1e76-4ddb-b6a5-998b65c4aff3",
"programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
"reference": "order-2041",
"reservationId": "checkout-1001",
"reserved": 0,
"rewardName": "Free chai",
"state": "active",
"transactionId": "add73925-4de9-412c-8cc2-582b074074ca"
},
"requestId": "31af666a-e95c-4e2b-9fb7-27d3f5f65935",
"success": true
}Hold part of a gift card's balance during checkout
/gift-cards/{id}/reservationsScopepasses:write
Requires passes:write and an Idempotency-Key; confirming or releasing it later needs loyalty:write (and passes:write), reading it loyalty:read (and passes:read). Gift card holds need a key without program or branch limits. Holds amount (the card's currency minor unit, currency must match, never converted) without moving the balance: GiftCard.available is balance less reserved, and the counter, POST /gift-cards/{id}/actions spends and the counter's void of a top-up all leave active holds funded (409 BENEFIT_RESERVED). Concurrent holds queue on the card's row lock (the one the counter's spend takes) and can never over-commit it: 409 INSUFFICIENT_BALANCE when the card itself is short, 409 INSUFFICIENT_AVAILABLE when other holds are in the way. The card's PIN is asked for at confirm, not here. reference makes the hold happen once under any key; the same reference for something else is 409 SOURCE_EVENT_CONFLICT. Same expiry, confirm, release and recovery rules as a program hold. Only gift cards are reservable among the issued passes: offers, generic passes, event tickets, boarding passes and transit passes answer POST /{family}/{id}/reservations with 422 UNSUPPORTED_ACTION and write nothing.
Send an Idempotency-Key header. Safe to retry.
Path
iduuidRequired
Body
amountintegerRequired- The part of the balance to hold, in the currency's minor unit.
currencystringRequired- The card's currency (ISO 4217).
referencestringRequired- Your checkout or order id.
branchIduuid- The branch the spend will happen at. Omitted: the business's only open branch (400 BRANCH_REQUIRED with several).
expiresInSecondsinteger- 60 to 86400.
Returns 201
reservationIdstringRequiredstateenumRequired- Read from the clock. One of
active,confirmed,released,expired. amountintegerRequired- Balance units held.
balanceintegerRequired- The membership's balance now; a hold never moves it.
reservedintegerRequired- Held by every active hold on the membership now.
availableintegerRequired- balance less reserved, never below zero.
balanceAfterinteger or nullRequiredcurrencystring or nullRequiredcustomerIdstring or nullRequired- Null for a gift card with no customer.
externalCustomerIdstringRequiredgiftCardIdstring or nullRequired- Set when the hold is on a gift card; then programId and membershipId are null.
membershipIdstring or nullRequiredprogramIdstring or nullRequiredreferencestringRequiredrewardNamestring or nullRequiredtransactionIdstring or nullRequired- The ledger row of the confirmed spend (the counter's pass event for a gift card).
createdAtstringRequiredexpiresAtstringRequireddecidedAtstring or nullRequiredduplicatebooleanRequired
Errors
- 409
BENEFIT_RESERVEDpart of the balance is held by a checkout reservation, so a counter or API spend would leave a hold unfunded. Nothing changed; confirm or release the hold, or let it expire. - 409
INSUFFICIENT_BALANCE - 409
INSUFFICIENT_AVAILABLEnot enough is available (the balance less active holds) to hold or spend this. Nothing changed. - 409
SOURCE_EVENT_CONFLICTthis source event id was already applied with different content (another customer, program, action or amount). Nothing changed. - 422
UNSUPPORTED_ACTIONthe action is not one a service may take (top-up, spend, set or adjust a balance, void) or the program's card type does not take earning and redeeming from the API yet. Nothing changed.
curl -X POST "https://app.revisit.cards/v1/developer/gift-cards/e01b010d-2c65-48e1-83a0-acad79f8d3b4/reservations" \
-H "Authorization: Bearer $DEVELOPER_API_KEY" \
-H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8eb27ce5" \
-H "Content-Type: application/json" \
-d '{
"amount": 1250,
"currency": "BDT",
"reference": "order-2041"
}'{
"data": {
"amount": 1250,
"available": 7,
"balance": 7,
"balanceAfter": 7,
"createdAt": "2026-11-03T08:41:12.000Z",
"currency": "BDT",
"customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
"decidedAt": "2026-11-03T08:41:12.000Z",
"duplicate": false,
"expiresAt": "2026-11-03T08:41:12.000Z",
"externalCustomerId": "user-42",
"giftCardId": "9c83a2c5-ee43-4698-bd57-cbed81fdc409",
"membershipId": "b53ca741-1e76-4ddb-b6a5-998b65c4aff3",
"programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
"reference": "order-2041",
"reservationId": "checkout-1001",
"reserved": 0,
"rewardName": "Free chai",
"state": "active",
"transactionId": "add73925-4de9-412c-8cc2-582b074074ca"
},
"requestId": "fe0e74fc-fddf-408f-aa6c-2625aa3866b6",
"success": true
}Not supported - an offer cannot be reserved
/offers/{id}/reservationsScopepasses:write
Requires passes:write. Always 422 UNSUPPORTED_ACTION (404 for an unknown id). The same route exists, with the same answer, under /generic-passes/{id}, /event-tickets/{id}, /boarding-passes/{id} and /transit-passes/{id}: those passes are used once, checked in or ridden, not drawn down like a balance, so there is nothing safe to hold. Nothing is written.
Path
iduuidRequired
Errors
- 422
UNSUPPORTED_ACTIONthe action is not one a service may take (top-up, spend, set or adjust a balance, void) or the program's card type does not take earning and redeeming from the API yet. Nothing changed.
curl -X POST "https://app.revisit.cards/v1/developer/offers/e01b010d-2c65-48e1-83a0-acad79f8d3b4/reservations" \
-H "Authorization: Bearer $DEVELOPER_API_KEY"{
"error": {
"code": "UNSUPPORTED_ACTION",
"message": "Not supported - an offer cannot be reserved"
},
"requestId": "3e87a6b0-eae0-4130-b0f3-1df6436ee81a",
"success": false
}Not supported - a generic pass cannot be reserved
/generic-passes/{id}/reservationsScopepasses:write
Requires passes:write. Always 422 UNSUPPORTED_ACTION (404 for an unknown id). The same route exists, with the same answer, under /generic-passes/{id}, /event-tickets/{id}, /boarding-passes/{id} and /transit-passes/{id}: those passes are used once, checked in or ridden, not drawn down like a balance, so there is nothing safe to hold. Nothing is written.
Path
iduuidRequired
Errors
- 422
UNSUPPORTED_ACTIONthe action is not one a service may take (top-up, spend, set or adjust a balance, void) or the program's card type does not take earning and redeeming from the API yet. Nothing changed.
curl -X POST "https://app.revisit.cards/v1/developer/generic-passes/e01b010d-2c65-48e1-83a0-acad79f8d3b4/reservations" \
-H "Authorization: Bearer $DEVELOPER_API_KEY"{
"error": {
"code": "UNSUPPORTED_ACTION",
"message": "Not supported - a generic pass cannot be reserved"
},
"requestId": "db4dbdad-ebc5-4020-a587-a3de74bd0cc5",
"success": false
}Not supported - an event ticket cannot be reserved
/event-tickets/{id}/reservationsScopepasses:write
Requires passes:write. Always 422 UNSUPPORTED_ACTION (404 for an unknown id). The same route exists, with the same answer, under /generic-passes/{id}, /event-tickets/{id}, /boarding-passes/{id} and /transit-passes/{id}: those passes are used once, checked in or ridden, not drawn down like a balance, so there is nothing safe to hold. Nothing is written.
Path
iduuidRequired
Errors
- 422
UNSUPPORTED_ACTIONthe action is not one a service may take (top-up, spend, set or adjust a balance, void) or the program's card type does not take earning and redeeming from the API yet. Nothing changed.
curl -X POST "https://app.revisit.cards/v1/developer/event-tickets/e01b010d-2c65-48e1-83a0-acad79f8d3b4/reservations" \
-H "Authorization: Bearer $DEVELOPER_API_KEY"{
"error": {
"code": "UNSUPPORTED_ACTION",
"message": "Not supported - an event ticket cannot be reserved"
},
"requestId": "441aca7a-f6ca-4d69-b01b-82882f96b2dd",
"success": false
}Not supported - a boarding pass cannot be reserved
/boarding-passes/{id}/reservationsScopepasses:write
Requires passes:write. Always 422 UNSUPPORTED_ACTION (404 for an unknown id). The same route exists, with the same answer, under /generic-passes/{id}, /event-tickets/{id}, /boarding-passes/{id} and /transit-passes/{id}: those passes are used once, checked in or ridden, not drawn down like a balance, so there is nothing safe to hold. Nothing is written.
Path
iduuidRequired
Errors
- 422
UNSUPPORTED_ACTIONthe action is not one a service may take (top-up, spend, set or adjust a balance, void) or the program's card type does not take earning and redeeming from the API yet. Nothing changed.
curl -X POST "https://app.revisit.cards/v1/developer/boarding-passes/e01b010d-2c65-48e1-83a0-acad79f8d3b4/reservations" \
-H "Authorization: Bearer $DEVELOPER_API_KEY"{
"error": {
"code": "UNSUPPORTED_ACTION",
"message": "Not supported - a boarding pass cannot be reserved"
},
"requestId": "2e334bb4-118f-401d-9c72-55a80e67648a",
"success": false
}Not supported - a transit pass cannot be reserved
/transit-passes/{id}/reservationsScopepasses:write
Requires passes:write. Always 422 UNSUPPORTED_ACTION (404 for an unknown id). The same route exists, with the same answer, under /generic-passes/{id}, /event-tickets/{id}, /boarding-passes/{id} and /transit-passes/{id}: those passes are used once, checked in or ridden, not drawn down like a balance, so there is nothing safe to hold. Nothing is written.
Path
iduuidRequired
Errors
- 422
UNSUPPORTED_ACTIONthe action is not one a service may take (top-up, spend, set or adjust a balance, void) or the program's card type does not take earning and redeeming from the API yet. Nothing changed.
curl -X POST "https://app.revisit.cards/v1/developer/transit-passes/e01b010d-2c65-48e1-83a0-acad79f8d3b4/reservations" \
-H "Authorization: Bearer $DEVELOPER_API_KEY"{
"error": {
"code": "UNSUPPORTED_ACTION",
"message": "Not supported - a transit pass cannot be reserved"
},
"requestId": "884f42e1-3dd2-4011-b6b5-a409cf2322c0",
"success": false
}List this application's reservations, newest first
/reservationsScopeloyalty:read
Requires loyalty:read. state follows the clock, so a hold past its time reads expired before the worker writes it down. At most 100 per page.
Query
externalCustomerIdstringprogramIduuidgiftCardIduuid- Only the holds on this gift card. Gift card holds are listed only to a key with
passes:readand no program or branch limits. stateenum- One of
active,confirmed,released,expired. limitinteger- 1 to 100.
offsetinteger
Returns 200
hasMorebooleanRequireditemsobject[]Requireditems[].reservationIdstringRequireditems[].stateenumRequired- Read from the clock. One of
active,confirmed,released,expired. items[].amountintegerRequired- Balance units held.
items[].balanceintegerRequired- The membership's balance now; a hold never moves it.
items[].reservedintegerRequired- Held by every active hold on the membership now.
items[].availableintegerRequired- balance less reserved, never below zero.
items[].balanceAfterinteger or nullRequireditems[].currencystring or nullRequireditems[].customerIdstring or nullRequired- Null for a gift card with no customer.
items[].externalCustomerIdstringRequireditems[].giftCardIdstring or nullRequired- Set when the hold is on a gift card; then programId and membershipId are null.
items[].membershipIdstring or nullRequireditems[].programIdstring or nullRequireditems[].referencestringRequireditems[].rewardNamestring or nullRequireditems[].transactionIdstring or nullRequired- The ledger row of the confirmed spend (the counter's pass event for a gift card).
items[].createdAtstringRequireditems[].expiresAtstringRequireditems[].decidedAtstring or nullRequireditems[].duplicatebooleanRequiredlimitintegerRequiredoffsetintegerRequired
curl "https://app.revisit.cards/v1/developer/reservations" \
-H "Authorization: Bearer $DEVELOPER_API_KEY"{
"data": {
"hasMore": false,
"items": [
{
"amount": 1250,
"available": 7,
"balance": 7,
"balanceAfter": 7,
"createdAt": "2026-11-03T08:41:12.000Z",
"currency": "BDT",
"customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
"decidedAt": "2026-11-03T08:41:12.000Z",
"duplicate": false,
"expiresAt": "2026-11-03T08:41:12.000Z",
"externalCustomerId": "user-42",
"giftCardId": "9c83a2c5-ee43-4698-bd57-cbed81fdc409",
"membershipId": "b53ca741-1e76-4ddb-b6a5-998b65c4aff3",
"programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
"reference": "order-2041",
"reservationId": "checkout-1001",
"reserved": 0,
"rewardName": "Free chai",
"state": "active",
"transactionId": "add73925-4de9-412c-8cc2-582b074074ca"
}
],
"limit": 50,
"offset": 0
},
"requestId": "bad43710-25ae-42bd-bb6e-3e37db4205c6",
"success": true
}Read one reservation
/reservations/{id}Scopeloyalty:read
Requires loyalty:read. A reservation belongs to the application that made it; another application or business reads it as 404.
Path
iduuidRequired
Returns 200
reservationIdstringRequiredstateenumRequired- Read from the clock. One of
active,confirmed,released,expired. amountintegerRequired- Balance units held.
balanceintegerRequired- The membership's balance now; a hold never moves it.
reservedintegerRequired- Held by every active hold on the membership now.
availableintegerRequired- balance less reserved, never below zero.
balanceAfterinteger or nullRequiredcurrencystring or nullRequiredcustomerIdstring or nullRequired- Null for a gift card with no customer.
externalCustomerIdstringRequiredgiftCardIdstring or nullRequired- Set when the hold is on a gift card; then programId and membershipId are null.
membershipIdstring or nullRequiredprogramIdstring or nullRequiredreferencestringRequiredrewardNamestring or nullRequiredtransactionIdstring or nullRequired- The ledger row of the confirmed spend (the counter's pass event for a gift card).
createdAtstringRequiredexpiresAtstringRequireddecidedAtstring or nullRequiredduplicatebooleanRequired
curl "https://app.revisit.cards/v1/developer/reservations/e01b010d-2c65-48e1-83a0-acad79f8d3b4" \
-H "Authorization: Bearer $DEVELOPER_API_KEY"{
"data": {
"amount": 1250,
"available": 7,
"balance": 7,
"balanceAfter": 7,
"createdAt": "2026-11-03T08:41:12.000Z",
"currency": "BDT",
"customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
"decidedAt": "2026-11-03T08:41:12.000Z",
"duplicate": false,
"expiresAt": "2026-11-03T08:41:12.000Z",
"externalCustomerId": "user-42",
"giftCardId": "9c83a2c5-ee43-4698-bd57-cbed81fdc409",
"membershipId": "b53ca741-1e76-4ddb-b6a5-998b65c4aff3",
"programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
"reference": "order-2041",
"reservationId": "checkout-1001",
"reserved": 0,
"rewardName": "Free chai",
"state": "active",
"transactionId": "add73925-4de9-412c-8cc2-582b074074ca"
},
"requestId": "f269bdb9-d91c-47a0-a110-4b38c7441f07",
"success": true
}Spend a held benefit after the checkout succeeded
/reservations/{id}/confirmScopeloyalty:write
Requires loyalty:write and an Idempotency-Key. Runs the ordinary redeem or spend and marks the reservation confirmed in one transaction, so the ledger row (transactionId, the one the merchant app shows) and the state commit together. A repeat, under any key, answers the same confirmed reservation (duplicate: true) and spends once; many at once spend once. A reservation that ran out is 409 RESERVATION_EXPIRED and nothing was spent: reconcile the checkout (refund the payment, or reserve again). A released one is 409 RESERVATION_NOT_ACTIVE. This is not one transaction with your payment gateway: Punchd never claims it is. A gift card hold is spent through the counter's own planner, PIN guard and ledger: send the card's pin in the optional body when it has one (403 PIN_REQUIRED / WRONG_PIN leave the hold active); the PIN is compared on the server and is never stored, echoed or part of the retry fingerprint.
Send an Idempotency-Key header. Safe to retry.
Path
iduuidRequired
Body
pinstring- Gift card holds only.
Returns 200
reservationIdstringRequiredstateenumRequired- Read from the clock. One of
active,confirmed,released,expired. amountintegerRequired- Balance units held.
balanceintegerRequired- The membership's balance now; a hold never moves it.
reservedintegerRequired- Held by every active hold on the membership now.
availableintegerRequired- balance less reserved, never below zero.
balanceAfterinteger or nullRequiredcurrencystring or nullRequiredcustomerIdstring or nullRequired- Null for a gift card with no customer.
externalCustomerIdstringRequiredgiftCardIdstring or nullRequired- Set when the hold is on a gift card; then programId and membershipId are null.
membershipIdstring or nullRequiredprogramIdstring or nullRequiredreferencestringRequiredrewardNamestring or nullRequiredtransactionIdstring or nullRequired- The ledger row of the confirmed spend (the counter's pass event for a gift card).
createdAtstringRequiredexpiresAtstringRequireddecidedAtstring or nullRequiredduplicatebooleanRequired
Errors
- 409
RESERVATION_EXPIREDthe reservation ran out before it was confirmed. Nothing was spent: reconcile the checkout (refund the payment, or reserve again). - 409
RESERVATION_NOT_ACTIVEthe reservation is already in another terminal state (confirmed, or released) than this call needs. - 403
PIN_REQUIRED
curl -X POST "https://app.revisit.cards/v1/developer/reservations/e01b010d-2c65-48e1-83a0-acad79f8d3b4/confirm" \
-H "Authorization: Bearer $DEVELOPER_API_KEY" \
-H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8e7d6c43" \
-H "Content-Type: application/json" \
-d '{
"pin": "••••"
}'{
"data": {
"amount": 1250,
"available": 7,
"balance": 7,
"balanceAfter": 7,
"createdAt": "2026-11-03T08:41:12.000Z",
"currency": "BDT",
"customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
"decidedAt": "2026-11-03T08:41:12.000Z",
"duplicate": false,
"expiresAt": "2026-11-03T08:41:12.000Z",
"externalCustomerId": "user-42",
"giftCardId": "9c83a2c5-ee43-4698-bd57-cbed81fdc409",
"membershipId": "b53ca741-1e76-4ddb-b6a5-998b65c4aff3",
"programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
"reference": "order-2041",
"reservationId": "checkout-1001",
"reserved": 0,
"rewardName": "Free chai",
"state": "active",
"transactionId": "add73925-4de9-412c-8cc2-582b074074ca"
},
"requestId": "3961adf9-f2c5-45c0-b66a-8e3e24cac265",
"success": true
}Free a held benefit after a failed or abandoned checkout
/reservations/{id}/releaseScopeloyalty:write
Requires loyalty:write and an Idempotency-Key. Frees the hold at once. Safe to repeat (a released or expired reservation answers its state, 200). A confirmed one is 409 RESERVATION_NOT_ACTIVE: the benefit was spent. Confirm, release and expiry are mutually exclusive terminal transitions of one row: whichever commits first wins.
Send an Idempotency-Key header. Safe to retry.
Path
iduuidRequired
Returns 200
reservationIdstringRequiredstateenumRequired- Read from the clock. One of
active,confirmed,released,expired. amountintegerRequired- Balance units held.
balanceintegerRequired- The membership's balance now; a hold never moves it.
reservedintegerRequired- Held by every active hold on the membership now.
availableintegerRequired- balance less reserved, never below zero.
balanceAfterinteger or nullRequiredcurrencystring or nullRequiredcustomerIdstring or nullRequired- Null for a gift card with no customer.
externalCustomerIdstringRequiredgiftCardIdstring or nullRequired- Set when the hold is on a gift card; then programId and membershipId are null.
membershipIdstring or nullRequiredprogramIdstring or nullRequiredreferencestringRequiredrewardNamestring or nullRequiredtransactionIdstring or nullRequired- The ledger row of the confirmed spend (the counter's pass event for a gift card).
createdAtstringRequiredexpiresAtstringRequireddecidedAtstring or nullRequiredduplicatebooleanRequired
Errors
- 409
RESERVATION_NOT_ACTIVEthe reservation is already in another terminal state (confirmed, or released) than this call needs.
curl -X POST "https://app.revisit.cards/v1/developer/reservations/e01b010d-2c65-48e1-83a0-acad79f8d3b4/release" \
-H "Authorization: Bearer $DEVELOPER_API_KEY" \
-H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8e64fe17"{
"data": {
"amount": 1250,
"available": 7,
"balance": 7,
"balanceAfter": 7,
"createdAt": "2026-11-03T08:41:12.000Z",
"currency": "BDT",
"customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
"decidedAt": "2026-11-03T08:41:12.000Z",
"duplicate": false,
"expiresAt": "2026-11-03T08:41:12.000Z",
"externalCustomerId": "user-42",
"giftCardId": "9c83a2c5-ee43-4698-bd57-cbed81fdc409",
"membershipId": "b53ca741-1e76-4ddb-b6a5-998b65c4aff3",
"programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
"reference": "order-2041",
"reservationId": "checkout-1001",
"reserved": 0,
"rewardName": "Free chai",
"state": "active",
"transactionId": "add73925-4de9-412c-8cc2-582b074074ca"
},
"requestId": "0fe18884-8567-42eb-8ae1-bf65db3f76b8",
"success": true
}