LoyaltyReversals
Loyalty
Reversals
Take back stamps, points and money for a refund.
A reversal takes back all or part of an earlier action for a refund you name with reversalId. It corrects the loyalty ledger only and never claims a payment was refunded. Reversals can never add up to more than the original.
When the customer already used what the action gave, nothing changes: the answer is 409 REVERSAL_BENEFIT_USED and one review case opens for the owner, which you can read here.
Paths are relative to https://app.revisit.cards/v1/developer.
Endpoints
- POSTReverse a stamp, points, cashback or prepaid action in full or in part
/programs/{id}/reversals - GETList the owner review cases your application opened
/reversal-reviews - GETRead one owner review case
/reversal-reviews/{reviewId} - POSTReverse a gift card top-up or spend in full or in part
/gift-cards/{id}/reversals
Reverse a stamp, points, cashback or prepaid action in full or in part
/programs/{id}/reversalsScopeloyalty:write
Requires loyalty:write and an Idempotency-Key. Takes back all or part of the stamps or points an earlier earn (sourceEventId) gave, for the refund you identify with reversalId. It corrects the loyalty ledger only; it never claims an external payment was refunded. Stamp programs reverse quantity stamps; Points programs that earn per taka reverse by amount, the order amount refunded in whole taka, and what stays is the earning's original rule applied to the part not refunded; a fixed points-per-visit earning is reversed whole. Omit quantity and amount to reverse everything left. The earning's own rules (its source event's rule snapshot) are used, never the program's current settings. Cumulative reversals can never exceed the earning (409 REVERSAL_EXCEEDS_ORIGINAL, also for an earning already fully reversed or voided at the counter). If the customer has already used the benefit (balance would go negative or a spend followed), the answer is 409 REVERSAL_BENEFIT_USED: the earning stays in force, nothing changes and one owner review case is opened (its reviewId and reviewState are in error.fieldErrors; read it at /reversal-reviews). A balance held by an active checkout reservation is never pulled under it (409 BENEFIT_RESERVED). reversalId makes the reversal happen once under any key (the original answer with duplicate: true); the same id for different content is 409 REVERSAL_CONFLICT. Cashback programs reverse an earn (by amount, the part of the bill refunded in the currency's minor unit; what stays is the earning's own percent of the bill not refunded, rounded half up once) or a redeem (the credit is given back); Prepaid programs reverse a topup (taken back while the customer still holds it) or a spend (given back). Both name the program's currency (422 CURRENCY_MISMATCH otherwise, nothing is converted); giving value back that would pass the balance cap is 409 BALANCE_LIMIT. A redeemed reward (Stamp, Points, Points and tiers) is given back whole, to the balance it had before the redeem (any next-card bonus stamp the redeem granted is netted off); a Subscription redeem gives the use back while its period is still open (an ended period, a later renewal or uses past the plan open an owner review, 409 REVERSAL_BENEFIT_USED); Tiered and Points and tiers earnings are reversed whole, never in part. Quantity or amount on any of these, a Subscription renew, and a Tiered redeem are 422 UNSUPPORTED_ACTION. Gift cards use /gift-cards/{id}/reversals. Unknown earnings, customers and programs outside the key's limits are 404.
Send an Idempotency-Key header. Safe to retry.
Path
iduuidRequired
Body
externalCustomerIdstringRequiredsourceEventIdstringRequired- The sourceEventId of the earning being reversed.
reversalIdstringRequired- Your own id for this refund. It makes the reversal happen once, even under a new Idempotency-Key.
originalActionenum- Which action sourceEventId was. Defaults to earn. Stamp, Points, Points and tiers: earn, or redeem (a reward, given back whole). Tiered: earn (whole). Subscription: redeem (one use, given back whole). Cashback: earn or redeem. Prepaid: topup or spend. Others (renew included) are 422 UNSUPPORTED_ACTION. One of
earn,redeem,renew,topup,spend. currencystring- Cashback and Prepaid only, required there. The program's currency (ISO 4217).
quantityinteger- Stamp programs. How many of the earning's stamps to take back.
amountinteger- Points programs that earn per taka: the order amount refunded, in whole taka. Cashback and Prepaid: in the currency's minor unit (the part of the bill for a Cashback earn, the value otherwise).
Returns 200
currencystring or nullRequired- Cashback and Prepaid; null otherwise.
reversalIdstringRequiredsourceEventIdstringRequiredprogramIdstringRequiredcustomerIdstringRequiredexternalCustomerIdstringRequiredmembershipIdstringRequireddeltaintegerRequired- Change to the balance by this reversal. Negative when value was taken back, positive when a reversed redeem or spend gave it back; 0 when a small partial refund changes no points or cashback.
balanceintegerRequired- The balance after this reversal.
unitenumRequired- What units, reversedUnits and remainingUnits count (minor is the currency's minor unit). One of
stamps,taka,visits,minor,uses,rewards. unitsintegerRequired- Refund units this reversal covers.
reversedUnitsintegerRequiredremainingUnitsintegerRequiredreversedTotalintegerRequired- Balance units (stamps or points) taken back from the earning so far.
reversibleLeftintegerRequired- Balance units of the earning still reversible.
stateenumRequired- One of
partial,complete. transactionIdstring or nullRequired- The VOID ledger row the merchant app shows; null when nothing was taken back.
duplicatebooleanRequired- True when this reversalId was already applied; nothing changed and this is the original result.
Errors
- 409
REVERSAL_EXCEEDS_ORIGINALa reversal would take back more of the earning than is left (it is already fully reversed, or the refund is larger than what remains). Nothing changed. - 409
REVERSAL_BENEFIT_USEDthe customer has already used the stamps or points the earning gave, so taking them back would leave a negative balance or undo a spent reward. The original earning stays in force and nothing changed; the owner decides (owner review). - 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
REVERSAL_CONFLICTthis reversalId was already used for a different request (another earning, amount or customer). Nothing changed. - 422
CURRENCY_MISMATCHa money action named a currency other than the program's. Nothing changed. - 409
BALANCE_LIMIT - 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/reversals" \
-H "Authorization: Bearer $DEVELOPER_API_KEY" \
-H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8e97b91a" \
-H "Content-Type: application/json" \
-d '{
"externalCustomerId": "user-42",
"reversalId": "refund-1001",
"sourceEventId": "order-1001"
}'{
"data": {
"balance": 7,
"currency": "BDT",
"customerId": "eb83b9c0-5619-432d-b857-cef7fcf84edb",
"delta": 1,
"duplicate": false,
"externalCustomerId": "user-42",
"membershipId": "b53ca741-1e76-4ddb-b6a5-998b65c4aff3",
"programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
"remainingUnits": 1,
"reversalId": "refund-1001",
"reversedTotal": 12,
"reversedUnits": 1,
"reversibleLeft": 1,
"sourceEventId": "order-1001",
"state": "partial",
"transactionId": "add73925-4de9-412c-8cc2-582b074074ca",
"unit": "stamps",
"units": 1
},
"requestId": "b8da09d1-6659-4e66-bc4f-771a3b7db8c0",
"success": true
}List the owner review cases your application opened
/reversal-reviewsScopeloyalty:read
Requires loyalty:read. A refund of a spent benefit (409 REVERSAL_BENEFIT_USED) opens one owner review case per reversalId; this lists the ones your application opened, newest first, for programs inside the key's limits, in the key's own environment. Read only: the owner decides in the merchant app, never a key.
Query
stateenum- One of
open,approved,declined. reversalIdstringlimitinteger- 1 to 100.
Returns 200
itemsobject[]Requireditems[].reviewIduuidRequired- The stable reference, also in error.fieldErrors.reviewId of the 409.
items[].reversalIdstringRequireditems[].sourceEventIdstringRequireditems[].externalCustomerIdstring or nullRequireditems[].programIdstring or nullRequireditems[].originalDeltaintegerRequired- Balance units the earning gave; it stays in force.
items[].requestedUnitsinteger or nullRequired- Refund units asked for; null when everything left was asked.
items[].unitenumRequired- One of
stamps,taka,visits,minor,uses,rewards. items[].currencystring or nullRequireditems[].giftCardIdstring or nullRequired- Set when the case is about a gift card top-up; then programId and externalCustomerId may be null.
items[].stateenumRequired- approved means the owner accepts that the customer keeps the benefit; declined means the refund claim was refused. Neither moves a balance. One of
open,approved,declined. items[].createdAtdate-timeRequireditems[].resolvedAtdate-time or nullRequired
Errors
- 409
REVERSAL_BENEFIT_USEDthe customer has already used the stamps or points the earning gave, so taking them back would leave a negative balance or undo a spent reward. The original earning stays in force and nothing changed; the owner decides (owner review).
curl "https://app.revisit.cards/v1/developer/reversal-reviews" \
-H "Authorization: Bearer $DEVELOPER_API_KEY"{
"data": {
"items": [
{
"createdAt": "2026-11-03T08:41:12.000Z",
"currency": "BDT",
"externalCustomerId": "user-42",
"giftCardId": "9c83a2c5-ee43-4698-bd57-cbed81fdc409",
"originalDelta": 1,
"programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
"requestedUnits": 1,
"resolvedAt": "2026-11-03T08:41:12.000Z",
"reversalId": "refund-1001",
"reviewId": "76d1cb71-bd79-4238-b56e-c2626b7972eb",
"sourceEventId": "order-1001",
"state": "open",
"unit": "stamps"
}
]
},
"requestId": "54d78365-5df8-4609-9747-016883aee3d0",
"success": true
}Read one owner review case
/reversal-reviews/{reviewId}Scopeloyalty:read
Requires loyalty:read. A case of another application, business or environment is 404.
Path
reviewIduuidRequired
Returns 200
reviewIduuidRequired- The stable reference, also in error.fieldErrors.reviewId of the 409.
reversalIdstringRequiredsourceEventIdstringRequiredexternalCustomerIdstring or nullRequiredprogramIdstring or nullRequiredoriginalDeltaintegerRequired- Balance units the earning gave; it stays in force.
requestedUnitsinteger or nullRequired- Refund units asked for; null when everything left was asked.
unitenumRequired- One of
stamps,taka,visits,minor,uses,rewards. currencystring or nullRequiredgiftCardIdstring or nullRequired- Set when the case is about a gift card top-up; then programId and externalCustomerId may be null.
stateenumRequired- approved means the owner accepts that the customer keeps the benefit; declined means the refund claim was refused. Neither moves a balance. One of
open,approved,declined. createdAtdate-timeRequiredresolvedAtdate-time or nullRequired
curl "https://app.revisit.cards/v1/developer/reversal-reviews/76d1cb71-bd79-4238-b56e-c2626b7972eb" \
-H "Authorization: Bearer $DEVELOPER_API_KEY"{
"data": {
"createdAt": "2026-11-03T08:41:12.000Z",
"currency": "BDT",
"externalCustomerId": "user-42",
"giftCardId": "9c83a2c5-ee43-4698-bd57-cbed81fdc409",
"originalDelta": 1,
"programId": "d7595bbd-4342-41b4-9037-2e61a9f8403f",
"requestedUnits": 1,
"resolvedAt": "2026-11-03T08:41:12.000Z",
"reversalId": "refund-1001",
"reviewId": "76d1cb71-bd79-4238-b56e-c2626b7972eb",
"sourceEventId": "order-1001",
"state": "open",
"unit": "stamps"
},
"requestId": "7be8e984-3bf6-47e2-8b23-43f5f726b2d0",
"success": true
}Reverse a gift card top-up or spend in full or in part
/gift-cards/{id}/reversalsScopepasses:write
Requires passes:write (whole-business keys, like every gift card route) and an Idempotency-Key. Takes back all or part (amount, minor units of the card's currency, required currency) of an earlier topup or spend (sourceEventId, originalAction) for the refund you identify with reversalId. A spend reversal gives the value back (up to the spend); a top-up reversal removes it only while the card still holds it and the customer has not spent since: otherwise 409 REVERSAL_BENEFIT_USED opens one owner review case (reviewId in error.fieldErrors) and nothing changes. Cumulative reversals never exceed the original (409 REVERSAL_EXCEEDS_ORIGINAL, also after an undo at the counter); a held balance is never pulled under its hold (409 BENEFIT_RESERVED); 422 CURRENCY_MISMATCH. reversalId makes it happen once under any key; the same id for other content is 409 REVERSAL_CONFLICT. The card's history gets a void row; the answer never carries a PIN, number or link. Punchd never refunds the payment.
Send an Idempotency-Key header. Safe to retry.
Path
iduuidRequired
Body
currencystringRequired- The card's currency (ISO 4217).
originalActionenumRequired- One of
topup,spend. sourceEventIdstringRequired- The sourceEventId of the top-up or spend being reversed.
reversalIdstringRequired- Your own id for this refund.
amountinteger- Minor units to reverse; omit for everything left.
Returns 200
giftCardIdstringRequiredreversalIdstringRequiredsourceEventIdstringRequiredoriginalActionenumRequired- One of
topup,spend. currencystringRequireddeltaintegerRequired- Positive when a spend was given back, negative when a top-up was taken back.
balanceintegerRequiredreversedTotalintegerRequiredreversibleLeftintegerRequiredstateenumRequired- One of
partial,complete. eventIdstringRequired- The void row in the card's history.
duplicatebooleanRequired
Errors
- 409
REVERSAL_BENEFIT_USEDthe customer has already used the stamps or points the earning gave, so taking them back would leave a negative balance or undo a spent reward. The original earning stays in force and nothing changed; the owner decides (owner review). - 409
REVERSAL_EXCEEDS_ORIGINALa reversal would take back more of the earning than is left (it is already fully reversed, or the refund is larger than what remains). Nothing changed. - 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. - 422
CURRENCY_MISMATCHa money action named a currency other than the program's. Nothing changed. - 409
REVERSAL_CONFLICTthis reversalId was already used for a different request (another earning, amount or customer). Nothing changed.
curl -X POST "https://app.revisit.cards/v1/developer/gift-cards/e01b010d-2c65-48e1-83a0-acad79f8d3b4/reversals" \
-H "Authorization: Bearer $DEVELOPER_API_KEY" \
-H "Idempotency-Key: 5f0c2a8e-7b1d-4c3e-9a6f-0d4b8ee13351" \
-H "Content-Type: application/json" \
-d '{
"currency": "BDT",
"originalAction": "topup",
"reversalId": "refund-1001",
"sourceEventId": "order-1001"
}'{
"data": {
"balance": 7,
"currency": "BDT",
"delta": 1,
"duplicate": false,
"eventId": "4251c053-b8cd-48e3-885b-da303b8448cc",
"giftCardId": "9c83a2c5-ee43-4698-bd57-cbed81fdc409",
"originalAction": "topup",
"reversalId": "refund-1001",
"reversedTotal": 12,
"reversibleLeft": 1,
"sourceEventId": "order-1001",
"state": "partial"
},
"requestId": "bd6ec1ec-1e20-4312-b731-9de1c217d60d",
"success": true
}