Skip to content
LoyaltyReversals

Loyalty

Reversals

Take back stamps, points and money for a refund.

Pilotv1

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.

Reverse a stamp, points, cashback or prepaid action in full or in part

POST/programs/{id}/reversals

Scopeloyalty: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

externalCustomerIdstringRequired
sourceEventIdstringRequired
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.
reversalIdstringRequired
sourceEventIdstringRequired
programIdstringRequired
customerIdstringRequired
externalCustomerIdstringRequired
membershipIdstringRequired
deltaintegerRequired
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.
reversedUnitsintegerRequired
remainingUnitsintegerRequired
reversedTotalintegerRequired
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

  • 409REVERSAL_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.
  • 409REVERSAL_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).
  • 409BENEFIT_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.
  • 409REVERSAL_CONFLICTthis reversalId was already used for a different request (another earning, amount or customer). Nothing changed.
  • 422CURRENCY_MISMATCHa money action named a currency other than the program's. Nothing changed.
  • 409BALANCE_LIMIT
  • 422UNSUPPORTED_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.
Request
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"
  }'
Response
{
  "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

GET/reversal-reviews

Scopeloyalty: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.
reversalIdstring
limitinteger
1 to 100.

Returns 200

itemsobject[]Required
items[].reviewIduuidRequired
The stable reference, also in error.fieldErrors.reviewId of the 409.
items[].reversalIdstringRequired
items[].sourceEventIdstringRequired
items[].externalCustomerIdstring or nullRequired
items[].programIdstring or nullRequired
items[].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 nullRequired
items[].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-timeRequired
items[].resolvedAtdate-time or nullRequired

Errors

  • 409REVERSAL_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).
Request
curl "https://app.revisit.cards/v1/developer/reversal-reviews" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY"
Response
{
  "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

GET/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.
reversalIdstringRequired
sourceEventIdstringRequired
externalCustomerIdstring or nullRequired
programIdstring or nullRequired
originalDeltaintegerRequired
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 nullRequired
giftCardIdstring 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-timeRequired
resolvedAtdate-time or nullRequired
Request
curl "https://app.revisit.cards/v1/developer/reversal-reviews/76d1cb71-bd79-4238-b56e-c2626b7972eb" \
  -H "Authorization: Bearer $DEVELOPER_API_KEY"
Response
{
  "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

POST/gift-cards/{id}/reversals

Scopepasses: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

giftCardIdstringRequired
reversalIdstringRequired
sourceEventIdstringRequired
originalActionenumRequired
One of topup, spend.
currencystringRequired
deltaintegerRequired
Positive when a spend was given back, negative when a top-up was taken back.
balanceintegerRequired
reversedTotalintegerRequired
reversibleLeftintegerRequired
stateenumRequired
One of partial, complete.
eventIdstringRequired
The void row in the card's history.
duplicatebooleanRequired

Errors

  • 409REVERSAL_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).
  • 409REVERSAL_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.
  • 409BENEFIT_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.
  • 422CURRENCY_MISMATCHa money action named a currency other than the program's. Nothing changed.
  • 409REVERSAL_CONFLICTthis reversalId was already used for a different request (another earning, amount or customer). Nothing changed.
Request
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"
  }'
Response
{
  "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
}