---
title: "Refund reward purchase"
method: POST
path: "/v2/loyalties/programs/{programId}/rewards/purchases/{rewardTransactionId}/refund"
tags: ["Programs"]
---

# Refund reward purchase

`POST /v2/loyalties/programs/{programId}/rewards/purchases/{rewardTransactionId}/refund`

## Request

- Base URL: `https://api.voucherify.io`
- URL: `https://api.voucherify.io/v2/loyalties/programs/{programId}/rewards/purchases/{rewardTransactionId}/refund`
- Auth: one of:
  - API key in header `X-App-Id` and API key in header `X-App-Token`
  - HTTP bearer

Refunds an `APPROVED` reward purchase made by a program member. The purchase transaction is marked `REFUNDED`, a new `REFUND` reward transaction is created with status `APPROVED`, and the points spent on the purchase are returned to the member's card.

The request body is optional and an empty payload is allowed. Policies default to `refund: DEFAULT` and `stock: DEFAULT`.

The endpoint responds with `202` before the card balance changes. A `POINTS_RETURNED` card transaction is created for the member's card and processed shortly after the response. When the member's tier or the card definition expires points, returned points receive a new expiration date from that setting. They don't inherit the expiration of the originally spent points. A `NO_EXPIRATION` setting leaves the returned points without an expiration date. Card earning limits don't block the refund.

For a `LOYALTY_CARD_POINTS` reward, the points credited to the target card are also reversed, with a `POINTS_PURCHASE_REVERSED` card transaction on that card. That transaction is processed shortly after the response. Its expiration is copied from the original points-purchased transaction.

A `DISCOUNT_COUPONS` refund deletes the issued vouchers. `details.result.digital.discount_coupons[].result` is `DELETED`, or `SKIPPED` when the voucher isn't deleted. A `GIFT_VOUCHERS` refund subtracts the credited amount. `details.result.digital.gift_vouchers[].result` is `CREDITS_SUBTRACTED`, or `SKIPPED` when the balance update is rejected.

The refund reverses that purchase in the reward's purchase limits for the project-local day of the original purchase. A day whose purchases are all refunded no longer counts as the member's last purchase.

Only rewards whose `refunds.type` is `REFUNDABLE` can be refunded. Any other reward is rejected with `423` and key `reward_refund_policy_does_not_allow_refunds`. `policies.refund` set to `ALLOW` refunds it anyway.

The program must exist, and the reward transaction must belong to that program. Otherwise the request fails with `404`. The program is checked first. The request is rejected with `423` when:
- The program isn't `ACTIVE` (`non_active_program`) or is outside its validity window (`program_outside_validity_window`),
- The transaction isn't a purchase (`non_purchase_reward_transaction`) or isn't `APPROVED` (`non_approved_reward_transaction`); refunding the same purchase twice fails here,
- The reward no longer exists (`reward_not_found`), isn't assigned to the program (`refund_reward_not_assigned_to_program`), the member's card is gone (`refund_card_not_found`), or the card definition is gone (`refund_card_definition_not_found`),
- The reward type isn't supported (`reward_type_not_supported_for_refunds`),
- For a `LOYALTY_CARD_POINTS` reward, the purchase result is missing (`loyalty_card_points_purchase_result_not_found`), the target card is gone (`loyalty_card_points_target_card_not_found`), the points-purchased card transaction is missing (`loyalty_card_points_purchase_not_found`), the target card's available balance is lower than the purchased points (`loyalty_card_points_insufficient_balance`), or the target card definition is gone (`loyalty_card_points_target_card_definition_not_found`).

## Request body

- V2LoyaltiesProgramsRewardsPurchasesRefundRequestBody: Fields for refunding a reward purchase.
  - `policies` RewardPurchaseRefundPolicies: Refund policies for a reward purchase refund.
    - `refund` 'DEFAULT' | 'ALLOW', nullable: Applies the refund override. `DEFAULT` follows the reward's refunds setting. `ALLOW` refunds even when the reward is not refundable. Defaults to `DEFAULT`.
    - `stock` 'DEFAULT' | 'WRITE_OFF', nullable: Controls assignment stock. `DEFAULT` restores one unit when stock is limited. `WRITE_OFF` does not restore stock. Unlimited (`null`) stock is unchanged. Defaults to `DEFAULT`.

## Response `202`

Refund accepted. The refund reward transaction has been created with status APPROVED and points will be returned to the member's card asynchronously.

- V2LoyaltiesProgramsRewardsPurchasesRefundResponseBody: Result of a reward purchase refund.
  - `transaction` RewardPurchaseTransaction, required: A reward transaction. Represents a reward purchase or a reward refund.
    - `program_id` string: Unique identifier of the loyalty program (format `lprg_...`).
    - `member_id` string: Unique identifier of the program member (format `lmbr_...`).
    - `created_at` string, date-time: Timestamp when the transaction was created (ISO 8601).
    - `updated_at` string, date-time, nullable: Timestamp when the transaction was last updated (ISO 8601), or `null`.
    - `card_id` string: Unique identifier of the loyalty card the points were spent from (format `lcrd_...`).
    - `id` string: Unique reward transaction identifier (format `lrtx_...`). Absent for `DRY_RUN` (SIMULATED) transactions, which are never persisted.
    - `card_definition_id` string, nullable: Unique identifier of the card definition for that card (format `lcdef_...`). `null` when none is stored.
    - `card_transaction_id` string, nullable: Identifies of the underlying card transaction (format `lctx_...`). `null` for `DRY_RUN` (SIMULATED) transactions.
    - `reward_id` string: Unique identifier of the purchased reward (format `lrew_...`).
    - `status` 'PENDING' | 'PROCESSING' | 'APPROVED' | 'REJECTED' | 'SIMULATED' | 'REFUNDED': Transaction status: - `PENDING`: Created and awaiting processing. - `PROCESSING`: Being processed. - `APPROVED`: Completed successfully. - `REJECTED`: Rejected (see `details.rejection`). - `SIMULATED`: Dry-run result that is not persisted. - `REFUNDED`: Purchase has been refunded.
    - `type` 'PURCHASE' | 'REFUND': Transaction type.
    - `details` union: Transaction details. Shape depends on `type` - purchase details for `PURCHASE`, refund details for `REFUND`.
      - RewardPurchaseTransactionDetailsPurchase: Details of a `PURCHASE` reward transaction.
        - `reason` string, required: Human-readable reason. For purchases: "Points spent on reward".
        - `rejection` RewardPurchaseRejection, required: Details about a rejected reward purchase transaction.
          - `reason` string, required: Machine-readable rejection reason.
          - `details` object: Additional structured context about the rejection. Fields depend on the rejection reason.
        - `metadata` object, required: Transaction metadata. Empty object when not set.
        - `points` RewardPurchasePoints, required: Points involved in the transaction.
          - `total` number, required: Total number of points.
        - `result` RewardPurchaseResult, required: Reward fulfillment result. Contains the fulfilled reward reference, quantity and the material or digital fulfillment payload.
          - `reward` RewardPurchaseResultReward: Reference to the fulfilled reward.
            - `id` string: Reward identifier (format `lrew_...`).
            - `type` 'MATERIAL' | 'DIGITAL': Reward type.
          - `quantity` number, nullable: Fulfilled quantity.
          - `material` RewardPurchaseResultMaterial: Material reward fulfillment.
            - `type` 'PRODUCT' | 'SKU': Material reward type.
            - `product` object: Product payload (present when `type` is `PRODUCT`).
            - `sku` object: SKU payload (present when `type` is `SKU`).
          - `digital` RewardPurchaseResultDigital: Digital reward fulfillment.
            - `type` 'DISCOUNT_COUPONS' | 'GIFT_VOUCHERS' | 'LOYALTY_CARD_POINTS': Digital reward type.
            - `discount_coupons` RewardPurchaseDigitalCoupon[]: Fulfilled discount coupons (present when `type` is `DISCOUNT_COUPONS`).
              - …
            - `gift_vouchers` RewardPurchaseDigitalGiftVoucher[]: Fulfilled gift vouchers (present when `type` is `GIFT_VOUCHERS`).
              - …
            - `loyalty_card_points` RewardPurchaseDigitalLoyaltyCardPoints: Loyalty card points fulfillment entry.
              - …
      - RewardPurchaseTransactionDetailsRefund: Details of a REFUND reward transaction.
        - `reason` string, required: Sets the refund reason. Always `Manual reward refund` for this endpoint.
        - `rejection` RewardPurchaseRejection, required: Details about a rejected reward purchase transaction.
          - `reason` string, required: Machine-readable rejection reason.
          - `details` object: Additional structured context about the rejection. Fields depend on the rejection reason.
        - `metadata` object, required: Transaction metadata. Empty object when not set.
        - `points` RewardPurchasePoints, required: Points involved in the transaction.
          - `total` number, required: Total number of points.
        - `result` RewardPurchaseResult, required: Reward fulfillment result. Contains the fulfilled reward reference, quantity and the material or digital fulfillment payload.
          - `reward` RewardPurchaseResultReward: Reference to the fulfilled reward.
            - `id` string: Reward identifier (format `lrew_...`).
            - `type` 'MATERIAL' | 'DIGITAL': Reward type.
          - `quantity` number, nullable: Fulfilled quantity.
          - `material` RewardPurchaseResultMaterial: Material reward fulfillment.
            - `type` 'PRODUCT' | 'SKU': Material reward type.
            - `product` object: Product payload (present when `type` is `PRODUCT`).
            - `sku` object: SKU payload (present when `type` is `SKU`).
          - `digital` RewardPurchaseResultDigital: Digital reward fulfillment.
            - `type` 'DISCOUNT_COUPONS' | 'GIFT_VOUCHERS' | 'LOYALTY_CARD_POINTS': Digital reward type.
            - `discount_coupons` RewardPurchaseDigitalCoupon[]: Fulfilled discount coupons (present when `type` is `DISCOUNT_COUPONS`).
              - …
            - `gift_vouchers` RewardPurchaseDigitalGiftVoucher[]: Fulfilled gift vouchers (present when `type` is `GIFT_VOUCHERS`).
              - …
            - `loyalty_card_points` RewardPurchaseDigitalLoyaltyCardPoints: Loyalty card points fulfillment entry.
              - …
        - `purchase` RewardPurchaseRefundPurchaseReference, required: References to the original purchase transactions being refunded.
          - `card_transaction` object, nullable: Reference to the original card transaction.
            - `id` string: Card transaction identifier (format `lctx_...`).
          - `reward_transaction` object, nullable: Reference to the original reward transaction.
            - `id` string: Reward transaction identifier (format `lrtx_...`).
    - `object` 'reward_transaction': Object type marker. Always `reward_transaction`.
  - `status` 'APPROVED', required: Result status. Always `APPROVED` on success.
  - `message` string, required: Returns the result message: "Reward refund transaction created. Points will be returned to the member's card shortly.".

## Other responses

- `400`: Invalid payload. `policies.refund` or `policies.stock` is not one of the allowed values.
- `404`: The program doesn't exist (`resource_type` `program`), or the reward transaction doesn't belong to that program (`resource_type` `reward_transaction`). The program is checked first.
- `423`: Locked. The program isn't `ACTIVE` (`non_active_program`) or is outside its validity window (`program_outside_validity_window`). The transaction isn't an `APPROVED` `PURCHASE` (`non_purchase_reward_transaction`, `non_approved_reward_transaction`). The reward refund policy doesn't allow refunds (`reward_refund_policy_does_not_allow_refunds`). The reward, its program assignment, the source card, or the card definition is missing (`reward_not_found`, `refund_reward_not_assigned_to_program`, `refund_card_not_found`, `refund_card_definition_not_found`). The reward type isn't supported (`reward_type_not_supported_for_refunds`). For a `LOYALTY_CARD_POINTS` reward, the purchase result, target card, points-purchased transaction, or target card definition is missing, or the target card's available balance is lower than the purchased points (`loyalty_card_points_purchase_result_not_found`, `loyalty_card_points_target_card_not_found`, `loyalty_card_points_purchase_not_found`, `loyalty_card_points_insufficient_balance`, `loyalty_card_points_target_card_definition_not_found`).
- `500`: Internal server error.

## Changes

- **2026-10-14** (v2) `d29b33490051`: 1 breaking, 13 warning, 1 info
  - the `allOf[#/components/schemas/RewardPurchaseRefundResult]/transaction` response's property type changed from `object` to no type for status `202`
  - removed the optional property `allOf[#/components/schemas/RewardPurchaseRefundResult]/transaction/card_definition_id` from the response with the `202` status
  - removed the optional property `allOf[#/components/schemas/RewardPurchaseRefundResult]/transaction/card_id` from the response with the `202` status
  - removed the optional property `allOf[#/components/schemas/RewardPurchaseRefundResult]/transaction/card_transaction_id` from the response with the `202` status
  - …11 more
- **2026-10-14** (v2) `be14b3318eb3`: 1 breaking, 14 info
  - the `allOf[#/components/schemas/RewardPurchaseRefundResult]/transaction` response's property type changed from no type to `object` for status `202`
  - added the optional property `allOf[#/components/schemas/RewardPurchaseRefundResult]/transaction/card_definition_id` to the response with the `202` status
  - added the optional property `allOf[#/components/schemas/RewardPurchaseRefundResult]/transaction/card_id` to the response with the `202` status
  - added the optional property `allOf[#/components/schemas/RewardPurchaseRefundResult]/transaction/card_transaction_id` to the response with the `202` status
  - …11 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/voucherifyio/apis/voucherify-loyalty-v2-api/changes/v2/loyalties/programs/:programId/rewards/purchases/:rewardTransactionId/refund/post.md)

---

[API](https://skmtc.dev/voucherifyio/apis/voucherify-loyalty-v2-api.md) - [All operations](https://skmtc.dev/voucherifyio/apis/voucherify-loyalty-v2-api/llms.txt) - [OpenAPI document](https://skmtc.dev/voucherifyio/apis/voucherify-loyalty-v2-api/revisions/e0d9f2d2532f?raw)
