---
title: "Purchase reward with points"
method: POST
path: "/v2/loyalties/programs/{programId}/members/{memberId}/rewards/purchases"
tags: ["Programs"]
---

# Purchase reward with points

`POST /v2/loyalties/programs/{programId}/members/{memberId}/rewards/purchases`

## Request

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

Purchases a reward for the program member by spending points from the member's card. The card comes from the matching reward cost's card definition.

The program, reward, and member must be `ACTIVE`. The program and reward must be inside their validity windows. The reward must be assigned to the program with stock available, a cost must match the customer, and the purchase must stay inside frequency, cooldown, balance, and spending limits.

Modes:
- `TRANSACTION` (default): creates a `PENDING` reward transaction and a `PENDING` card transaction. Returns `202`.
- `DRY_RUN`: simulates the purchase and doesn't create a transaction. Returns `200` with status `SIMULATED`.

## Request body

- V2LoyaltiesProgramsMembersRewardsPurchasesCreateRequestBody: Fields for purchasing a reward.
  - `reward_id` string, required: Unique identifier of the reward to purchase (format `lrew_...`).
  - `mode` 'TRANSACTION' | 'DRY_RUN': Purchase mode. `TRANSACTION` creates a `PENDING` reward transaction processed asynchronously (HTTP `202`). `DRY_RUN` only simulates the purchase and returns the calculation result (HTTP `200`); no transaction is created. Defaults to `TRANSACTION` when omitted.

## Response `200`

Dry run result (mode `DRY_RUN`). No transaction was created; the returned transaction has status `SIMULATED` and no `id`.

- V2LoyaltiesProgramsMembersRewardsPurchasesCreateDryRunResponseBody: Result of a reward purchase request in dry-run mode.
  - `transaction` object, required: The simulated reward transaction.
    - `card_id` string, required: Unique identifier of the loyalty card the points are to be spent from (format `lcrd_...`).
    - `card_definition_id` string, required: Unique identifier of the card definition for that card (format `lcdef_...`).
    - `card_transaction_id` unknown, required
    - `program_id` string, required: Unique identifier of the loyalty program (format `lprg_...`).
    - `member_id` string, required: Unique identifier of the program member (format `lmbr_...`).
    - `reward_id` string, required: Unique identifier of the purchased reward (format `lrew_...`).
    - `status` 'SIMULATED', required: Transaction status is `SIMULATED` for a dry-run result that is not persisted.
    - `type` 'PURCHASE', required: Transaction type. It contains purchase details for the simulated transaction.
    - `details` RewardPurchaseTransactionDetailsPurchase, required: 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`).
            - `id` string: Voucher identifier of the coupon.
            - `code` string: Coupon code.
            - `result` 'SKIPPED' | 'DELETED': Refund handling result for this coupon (present in refund results): - `DELETED`: The coupon was deleted. - `SKIPPED`: The coupon was left intact.
          - `gift_vouchers` RewardPurchaseDigitalGiftVoucher[]: Fulfilled gift vouchers (present when `type` is `GIFT_VOUCHERS`).
            - `id` string: Voucher identifier of the gift voucher.
            - `code` string: Gift voucher code.
            - `amount` number: Amount added to (or, for refunds, subtracted from) the gift voucher balance.
            - `balance` number: Gift voucher balance after the operation.
            - `result` 'SKIPPED' | 'CREDITS_SUBTRACTED': Refund handling result for this gift voucher (present in refund results): - `CREDITS_SUBTRACTED`: The credited balance was subtracted. - `SKIPPED`: The voucher was left intact.
          - `loyalty_card_points` RewardPurchaseDigitalLoyaltyCardPoints: Loyalty card points fulfillment entry.
            - `points` number: Number of points credited to the target loyalty card.
            - `card_definition_id` string: Target card definition identifier (format `lcdef_...`).
            - `card_id` string: Target loyalty card identifier (format `lcrd_...`).
    - `updated_at` unknown, required
    - `object` 'reward_transaction', required: Object type marker. Always `reward_transaction`.
  - `status` 'DRY_RUN', required: Result status. Always `DRY_RUN` for the dry-run mode.
  - `message` string, required: Human-readable result message. `DRY_RUN` mode: "Dry run mode. No transaction was created. This is only a simulation.".

## Other responses

- `202`: Purchase accepted (mode `TRANSACTION`). A `PENDING` reward transaction was created and will be processed asynchronously.
- `400`: Request body validation failed.
- `404`: Checked in order. The program doesn't exist (`resource_type` `program`). The member doesn't exist in that program (`member`). The reward doesn't exist, or it isn't assigned to the program (`reward`, `resource_id` is the reward id). The member has no card for the cost's card definition, or that card record is missing (`card`; `resource_id` is the card definition id, or the card id). The card definition doesn't exist (`card_definition`). For a `LOYALTY_CARD_POINTS` reward, a missing target card is also `card`.
- `423`: The purchase is locked. `non_active_program`, `program_outside_validity_window`, `non_active_member`, `non_active_reward`, and `reward_outside_validity_window` reject a resource that isn't `ACTIVE` or is outside its validity window. `reward_out_of_stock` means assignment stock isn't available. `purchase_limit_cooldown` and `purchase_limit_frequency` mean a purchase limit blocked the request. `no_matching_reward_cost` means no cost matches this customer. `insufficient_card_balance` means the card doesn't have enough points. `exceeded_card_spending_global_spending_based_limit`, `exceeded_card_spending_global_time_based_limit`, and `exceeded_card_spending_transactions_limit` mean a spending cap was exceeded. `exceeded_spending_limits` is the fallback when the cap has no specific key.
- `500`: Internal server error.

## Changes

- **2026-10-14** (v2) `6a418ac8b7b1`: 7 breaking, 2 warning, 2 info
  - added `#/components/schemas/MemberRewardPurchaseRequest` to the request body `allOf` list
  - removed the required property `message` from the response with the `200` status
  - removed the required property `message` from the response with the `202` status
  - removed the required property `status` from the response with the `200` status
  - …7 more
- **2026-10-13** (v2) `f95b50556c93`: 1 breaking, 1 warning, 9 info
  - added the new required request property `reward_id`
  - removed `#/components/schemas/MemberRewardPurchaseRequest` from the request body `allOf` list
  - added the new optional request property `mode`
  - removed `#/components/schemas/MemberRewardPurchaseDryRunResult` from the response body `allOf` list for the response status `200`
  - …7 more
- **2026-10-13** (v2) `9905dfce1d1e`: 7 breaking, 2 warning, 2 info
  - added `#/components/schemas/MemberRewardPurchaseRequest` to the request body `allOf` list
  - removed the required property `message` from the response with the `200` status
  - removed the required property `message` from the response with the `202` status
  - removed the required property `status` from the response with the `200` status
  - …7 more
- …earlier changes not shown

[Operation history](https://skmtc.dev/voucherifyio/apis/voucherify-loyalty-v2-api/changes/v2/loyalties/programs/:programId/members/:memberId/rewards/purchases/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)
