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

# Redeem voucher

> Deduct an amount from a voucher's balance. Supports idempotency.

**Required scope:** `vouchers:redeem`
**Rate limit:** 60 requests/minute
**Idempotency:** supported via `Idempotency-Key` header (24h TTL, scoped per
API key). See [Idempotency](/developer-api/idempotency).

A redemption deducts from the voucher's `balance`. If the new balance reaches
zero the voucher status moves to `redeemed`; otherwise it stays `completed`
with the reduced balance.

## Path parameters

| Parameter | Type   | Notes                           |
| --------- | ------ | ------------------------------- |
| `code`    | string | Voucher code, max 50 characters |

## Headers

| Header            | Required | Notes                                                       |
| ----------------- | -------- | ----------------------------------------------------------- |
| `Idempotency-Key` | no       | Up to 256 characters. Cached response replays for 24 hours. |

## Request body

| Field    | Type             | Required | Notes                  |
| -------- | ---------------- | -------- | ---------------------- |
| `amount` | decimal (string) | yes      | Greater than 0         |
| `notes`  | string           | no       | Optional internal note |

## Response

```json theme={null}
{
  "id": "8d82f0d2-7f94-4a3b-8b55-1e2e3a4f5b6c",
  "code": "VG-EXAMPLE1",
  "amount": "100.00",
  "balance": "75.00",
  "status": "completed",
  "recipient_name": "Sam Recipient",
  "recipient_email": "sam@example.com",
  "expiry_date": "2029-04-26T00:00:00Z",
  "created_at": "2026-04-26T01:23:45Z",
  "updated_at": "2026-04-26T02:34:56Z",
  "location_id": null
}
```

## Errors

* `400 "Voucher is pending and not redeemable"` – voucher status is `pending`.
* `400 "Voucher is not redeemable"` – voucher status is anything other than
  `pending` or `completed` (e.g. already `redeemed`, `voided`, `refunded`).
* `400 "Cannot redeem an expired voucher"` – `expiry_date` has passed.
* `400 "Redemption amount exceeds available balance"` – `amount` is greater
  than the voucher's current `balance`.
* `404` – Voucher not found in your tenant (or location).
* `409 "A duplicate request is already being processed. Please wait a moment and try again."` – a request with the same `Idempotency-Key` is still in flight. Retry
  shortly.
* `409 "Idempotency-Key was reused with a different request body. Use a fresh Idempotency-Key for a different operation."` – `Idempotency-Key` reused with a different request body within the 24h
  replay window. See [Idempotency](/developer-api/idempotency).
* `409 "Voucher balance changed concurrently – please retry"` – the voucher
  balance changed underneath the operation (e.g. concurrent redemption).
  Retry.

## Examples

```bash theme={null}
curl -X POST \
  -H "X-API-Key: vg_live_EXAMPLEdoNotUseThis123456" \
  -H "Idempotency-Key: redeem-2026-04-26-VG-EXAMPLE1-001" \
  -H "Content-Type: application/json" \
  -d '{"amount": "25.00"}' \
  https://api.vouchergrid.com/api/v1/developer/vouchers/VG-EXAMPLE1/redeem
```

```ts theme={null}
const res = await fetch(
  "https://api.vouchergrid.com/api/v1/developer/vouchers/VG-EXAMPLE1/redeem",
  {
    method: "POST",
    headers: {
      "X-API-Key": process.env.VOUCHERGRID_API_KEY!,
      "Idempotency-Key": crypto.randomUUID(),
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ amount: "25.00" }),
  },
);
const voucher = await res.json();
```
