> ## Documentation Index
> Fetch the complete documentation index at: https://docs.scrip.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Redemptions

> Debit balances through amount redemptions and catalog purchases

Redemptions debit a participant's balance via the API. They come in two forms: an amount-based redemption for open-ended cashouts (statement credits, charitable donations), and a catalog item redemption for purchasing a specific reward. Both are triggered by your application, not by rules.

## Amount Redemption

Debit a specific amount from a participant's balance:

```bash theme={null}
POST /v1/participants/{id}/redemptions
{
  "program_id": "program-uuid",
  "asset_id": "asset-uuid",
  "amount": "1000",
  "description": "Cash out request #12345",
  "idempotency_key": "cashout-12345"
}
```

| Field             | Required | Description                                                                          |
| ----------------- | -------- | ------------------------------------------------------------------------------------ |
| `program_id`      | Yes      | Program context                                                                      |
| `asset_id`        | Yes      | Which asset to debit                                                                 |
| `amount`          | Yes      | Positive decimal amount                                                              |
| `description`     | Yes      | Reason for the redemption (1-500 characters)                                         |
| `idempotency_key` | No       | Prevents duplicate redemptions on retry. Same key + different payload returns `409`. |

The amount is debited from the participant's `AVAILABLE` balance and credited to the program's configured redemption target.

## Catalog Item Redemption

Redeem a specific item from the reward catalog:

```bash theme={null}
POST /v1/participants/{id}/redemptions/items
{
  "program_id": "program-uuid",
  "reward_id": "reward-uuid",
  "quantity": 2,
  "idempotency_key": "order-789"
}
```

For `UNIT_BASED` rewards, specify `quantity` (defaults to 1 if omitted). For `AMOUNT_BASED` rewards, specify `amount` instead.

For `UNIT_BASED` rewards, the cost is `quantity * unit_cost`. For `AMOUNT_BASED` rewards, the redeemed amount itself is the cost. Either way, the cost is stored on the redemption record. For `UNIT_BASED` rewards, inventory is tracked: `redeemed_count` increments globally and per participant, and the reward status changes to `OUT_OF_STOCK` when `max_total` is reached.

See [Rewards Catalog](/guides/rewards-catalog) for setting up catalog items.

## Redemption Targets

Each program configures where redeemed funds flow via `redemption_target_type`. Most programs use `SYSTEM_REDEMPTION` to keep redeemed value separate from breakage.

| Target              | Description                                                                                |
| ------------------- | ------------------------------------------------------------------------------------------ |
| `SYSTEM_REDEMPTION` | Default. Tracks redeemed value in a dedicated system account.                              |
| `SYSTEM_BREAKAGE`   | Combines with forfeited value in the breakage account.                                     |
| `LEDGER_ENTITY`     | Routes to a specific ledger entity. Requires `redemption_target_entity_id` on the program. |

The target is captured on the redemption record at creation time. If you change the program's target configuration later, existing redemptions and their reversals still use the original target. This keeps the ledger consistent.

Change a program's target with [Update a program](/api-reference/programs/update-a-program). The program must not be archived when you change target configuration:

```bash theme={null}
PATCH /v1/programs/{id}
{
  "redemption_target_type": "LEDGER_ENTITY",
  "redemption_target_entity_id": "entity-uuid"
}
```

`LEDGER_ENTITY` requires `redemption_target_entity_id` in the same request. Switching to `SYSTEM_REDEMPTION` or `SYSTEM_BREAKAGE` must omit `redemption_target_entity_id` and clears any existing reference. New programs default to `SYSTEM_REDEMPTION`; the target cannot be set at creation time.

Archived programs reject redemption target changes with `409 program_archived`. Reactivate the program before changing `redemption_target_type` or `redemption_target_entity_id`.

## Reversals

Reverse a redemption to return funds to the participant:

```bash theme={null}
# Full reversal
POST /v1/redemptions/{id}/reverse
{
  "reason": "Order cancelled by customer",
  "idempotency_key": "refund-123"
}

# Partial reversal (amount-based)
POST /v1/redemptions/{id}/reverse
{
  "amount": "500",
  "reason": "Partial refund for damaged item",
  "idempotency_key": "refund-456"
}

# Partial reversal (unit-based, whole units only)
POST /v1/redemptions/{id}/reverse
{
  "quantity": 1,
  "reason": "Customer returned 1 gift card",
  "idempotency_key": "refund-789"
}
```

Omit `amount` or `quantity` for a full reversal. Include it for a partial reversal. The field must match the original redemption type: `UNIT_BASED` catalog redemptions accept `quantity`, `AMOUNT_BASED` and amount redemptions accept `amount`.

`reason` is required (1-500 characters). Reversals are often reviewed during disputes or audits, so every reversal needs a human-readable explanation on record.

### Reversal Status

Each reversal updates the redemption's `status`:

| Status               | Meaning                                                  |
| -------------------- | -------------------------------------------------------- |
| `COMPLETED`          | No reversals applied                                     |
| `PARTIALLY_REVERSED` | Some amount or quantity reversed, more can follow        |
| `FULLY_REVERSED`     | Entire redemption reversed, no further reversals allowed |

The redemption tracks cumulative totals in `reversed_amount` and, for catalog items, `reversed_quantity`.

### Inventory Restoration

For `UNIT_BASED` catalog items, reversals decrement `redeemed_count` and the per-participant `redemption_count`. If a reward was `OUT_OF_STOCK` and the reversal brings inventory below `max_total`, the reward status returns to `ACTIVE`.

### Lot Restoration

For `LOT`-mode assets, reversals restore the specific lots spent by the original redemption. Lots are restored in reverse spend order and retain their original metadata including `expires_at` and `matures_at`.

## Viewing Redemptions

You can list redemptions per participant, fetch a single redemption by ID, or list the reversals attached to a redemption.

```bash theme={null}
# List participant redemptions
GET /v1/participants/{id}/redemptions

# Get redemption details
GET /v1/redemptions/{id}

# List reversals for a redemption
GET /v1/redemptions/{id}/reversals
```

## Requirements

Redemptions enforce these checks:

* Participant must be `ACTIVE`
* Program must be `ACTIVE` (not `SUSPENDED` or `ARCHIVED`)
* Asset must not be archived
* Sufficient `AVAILABLE` balance for the requested amount
* For catalog items: reward must be `ACTIVE` and within its availability window

Reversals enforce a shorter list:

* Participant must be `ACTIVE`
* The redemption must not already be `FULLY_REVERSED`
* A partial `amount` or `quantity` must not exceed the remaining unreversed amount or quantity

Idempotency keys are scoped per program. Replaying a request with the same key returns the original record without creating a duplicate.
