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

# Redemption links

> Create shareable links that let your customers pick and redeem a voucher on an AllRide-hosted, branded landing page.

A Redemption Link is a URL you hand to a customer, for example in an email or your app. The customer opens it on a landing page in your branding, picks a voucher from the providers and sets you allow, and receives the code or link. You need no frontend of your own. Creating and changing links needs `manage-consumer-redemption-links`; reading them needs `view-consumer-redemption-links`. Both can be granted to API keys.

## Link modes

The mode is decided when you create the link and never changes:

| Mode | Created when | Who can redeem | `maxRedemptions` means |
| - | - | - | - |
| `entity-bound` | You send `redemptionEntityId` or an inline `redemptionEntity` | Whoever opens the link; every redemption is attributed to that [Redemption Entity](https://docs-consumer.voucher.allride.io/consumer/redemption-entities.md) | Total redemptions for the entity through this link |
| `email-otp` | You send `requireEmailOtp: true` and no entity | Visitors who verify an email address with a one-time code; the verified address becomes (or finds) an entity | Redemptions **per verified entity**; `maxTotalRedemptions` caps the whole link |
| `anonymous` | Neither | Anyone with the link | Total redemptions for the link, shared by all visitors |

Sending an entity together with `requireEmailOtp: true` answers 422 [`link-mode-conflict`](https://docs-consumer.voucher.allride.io/errors/catalog#link-mode-conflict). An `email-otp` link needs the Email OTP Gate to be set up first, else 422 [`email-otp-not-configured`](https://docs-consumer.voucher.allride.io/errors/catalog#email-otp-not-configured); see [Email OTP links](https://docs-consumer.voucher.allride.io/consumer/email-otp-links.md).

Create a link with [`POST /consumer/v1/redemption-links`](https://docs-consumer.voucher.allride.io/api-reference/consumer-redemption-links-create):

```bash theme={null}
curl -X POST "$VOUCHER_API_BASE_URL/consumer/v1/redemption-links" \
  -H "Authorization: Bearer $VOUCHER_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: job-ticket-2026-11:emp-42" \
  -d '{
    "name": "Job ticket November - employee 42",
    "redemptionEntity": { "refId": "emp-42" },
    "allowedProviderIds": [1030, 1056],
    "allowedVoucherSetIds": [],
    "maxRedemptions": 1,
    "metadata": { "programme": "job-ticket-nov" },
    "expiresAt": "2026-11-30T22:59:59Z",
    "defaultLocale": "de"
  }'
```

The 201 response contains the link with its `token`, `url`, `mode`, `status` and counters. To create many links at once, for example one entity-bound link per employee, use [`POST /consumer/v1/redemption-links:batch`](https://docs-consumer.voucher.allride.io/api-reference/consumer-redemption-links-batch) with up to 100 items: it is all-or-nothing and returns a summary per link (`id`, `token`, `url`, `name`, `mode`, `redemptionEntity`, `status`).

Before your first link, set the privacy and imprint URLs of your landing page in Workspace Branding; otherwise creating a link answers 422 [`landing-legal-urls-missing`](https://docs-consumer.voucher.allride.io/errors/catalog#landing-legal-urls-missing). See [Landing pages and custom domains](https://docs-consumer.voucher.allride.io/consumer/landing-pages.md).

## Restricting providers and voucher sets

* `allowedProviderIds` (up to 50) limits the link to these providers. Each must have at least one visible, switched-on set in your catalog.
* `allowedVoucherSetIds` (up to 200) limits the link to these sets. Each must be visible with both Catalog Toggles on; if you also send `allowedProviderIds`, each set's provider must be among them.
* Empty lists mean "everything in my catalog that is switched on".

Invalid ids answer 400 [`data-failed-validation`](https://docs-consumer.voucher.allride.io/errors/catalog#data-failed-validation) with the constraint `provider-not-in-catalog`, `voucher-set-not-in-catalog` or `voucher-set-provider-not-allowed` for the offending list item.

The restriction is checked again whenever the customer opens the link. The landing catalog shows a set only when it is `active` or `deactivation-scheduled`, both toggles are on, it is not depleted and you have a redeemable Price Acceptance for it. Sets you have not accepted prices for are silently left out, because customers never see prices. Check what a link offers right now with [`GET /consumer/v1/redemption-links/{redemptionLinkId}/catalog`](https://docs-consumer.voucher.allride.io/api-reference/consumer-redemption-links-catalog): it returns the entries in landing order (at most 200) and lists in `hiddenForPriceAcceptance` the sets that are missing only because of prices.

Creating a link is never blocked by missing Price Acceptances; the link offers those sets as soon as you accept their prices.

## Limits and expiry

* **`maxRedemptions`** (1 or more, `null` = unlimited) caps redemptions as described per mode above. When an `anonymous` or `entity-bound` link reaches it, the link becomes `exhausted` and further redemptions answer 409 [`redemption-link-exhausted`](https://docs-consumer.voucher.allride.io/errors/catalog#redemption-link-exhausted). On an `email-otp` link, a visitor who reached their own cap gets 409 [`redemption-link-entity-limit-reached`](https://docs-consumer.voucher.allride.io/errors/catalog#redemption-link-entity-limit-reached) while the link stays `active`.
* **`maxTotalRedemptions`** (only for `email-otp` links) caps the whole link; reaching it makes the link `exhausted`. Sending it for another mode answers 400 `data-failed-validation` with the constraint `not-allowed-for-mode`. Set it for public `email-otp` links: without it, anyone with an email address can redeem.
* **`expiresAt`** (in the future) ends the link. From that moment it is `expired`, also before the status is persisted, and the landing page answers 410 [`redemption-link-expired`](https://docs-consumer.voucher.allride.io/errors/catalog#redemption-link-expired).
* Per-set **entity limits** (`entityLimit` in your [catalog settings](https://docs-consumer.voucher.allride.io/consumer/catalog.md#your-own-settings-and-references)) apply on top whenever the link knows the entity.

Change a link with [`PATCH`](https://docs-consumer.voucher.allride.io/api-reference/consumer-redemption-links-update): `name`, the allowed lists, `maxRedemptions`, `maxTotalRedemptions`, `metadata`, `expiresAt`, `customDomainId` and `defaultLocale`. The mode, entity, `requireEmailOtp` and token are fixed. Raising the cap of an `exhausted` link or moving `expiresAt` of an `expired` link into the future makes it `active` again; lowering a cap below the current `redemptionCount` answers 422 [`max-below-count`](https://docs-consumer.voucher.allride.io/errors/catalog#max-below-count); a cap equal to the count makes the link `exhausted`.

[`POST …/{redemptionLinkId}:revoke`](https://docs-consumer.voucher.allride.io/api-reference/consumer-redemption-links-revoke) ends a link immediately and for good: the landing page answers 410 [`redemption-link-revoked`](https://docs-consumer.voucher.allride.io/errors/catalog#redemption-link-revoked), and open visitor sessions stop working. Erasing an entity revokes all of its `entity-bound` links.

You receive the webhooks [`redemption-link-exhausted`](https://docs-consumer.voucher.allride.io/webhooks/events/redemption-link-exhausted) and [`redemption-link-expired`](https://docs-consumer.voucher.allride.io/webhooks/events/redemption-link-expired).

## Metadata forwarding

`metadata` on the link is your own JSON object (up to 16 KiB). Every redemption made through the link takes a snapshot of it, and the [`redemption-created`](https://docs-consumer.voucher.allride.io/webhooks/events/redemption-created) webhook carries it as `redemptionLink.metadata`, together with `redemptionEntity.refId` for entity-bound and `email-otp` links:

```json theme={null}
{
  "event": { "id": "5b8e0d3a-2c71-4f9e-8a46-d1e7c3b90f25", "type": "redemption-created", "timestamp": 1793693564 },
  "payload": {
    "resource": "redemption",
    "id": 6101,
    "status": "completed",
    "channel": "redemption-link",
    "voucherSetId": 2030,
    "redemptionEntity": { "id": 9030, "resource": "redemption-entity", "refId": "emp-42" },
    "redemptionLink": { "id": 8017, "resource": "redemption-link", "metadata": { "programme": "job-ticket-nov" } }
  }
}
```

The example shows only some fields of `payload`; see the event page for the full payload. Changing a link's `metadata` affects future redemptions only. Never put personal data in link metadata.

## Sharing the link

The link's `url` is `https://<host>/r/<token>`. The host is the link's `customDomainId` when that domain is active, else your default landing domain, else `redeem.voucher.allride.io`. See [Custom domains](https://docs-consumer.voucher.allride.io/workspace/custom-domains.md).

The 22-character `token` is a bearer capability: anyone who has the URL can use the link within its limits. Send it only to the intended customer, over a channel you trust, and do not post `entity-bound` links publicly. If a link leaks, revoke it and create a new one.

## What the customer sees

1. The customer opens the URL and sees a landing page with your logo, colours and texts, your terms, privacy and imprint links, and the link's `defaultLocale` (German or English).
2. For an `email-otp` link, they enter their email address, receive a 6-digit code from your SMTP server and enter it. See [Email OTP links](https://docs-consumer.voucher.allride.io/consumer/email-otp-links.md).
3. They browse the offered providers and voucher sets and pick one.
4. If you turned on bot protection in Workspace Branding (`landing.botProtection: turnstile`), the page runs a Cloudflare Turnstile check before each redemption and each code request; with the default `off`, no check is shown.
5. They receive the code or link, with the provider's redemption instructions and validity.

Reloading the page shows the vouchers already issued in the visitor's session (or to their entity) again, so a customer never loses a code. On `anonymous` and `entity-bound` links the visitor's session lasts as long as the link is valid: no "session ended" message while the link can be used. Revoking the link, its expiry or blocking the entity still ends access at once. On `email-otp` links the session lasts as long as you set in [Email OTP links](https://docs-consumer.voucher.allride.io/consumer/email-otp-links.md#session-length). An exhausted link still shows the vouchers issued earlier; an expired or revoked link shows a branded "link unavailable" page with your support contacts.

## Related

* [Email OTP links](https://docs-consumer.voucher.allride.io/consumer/email-otp-links.md)
* [Landing pages and custom domains](https://docs-consumer.voucher.allride.io/consumer/landing-pages.md)
* [Redemption entities](https://docs-consumer.voucher.allride.io/consumer/redemption-entities.md)
* [Create a redemption link](https://docs-consumer.voucher.allride.io/api-reference/consumer-redemption-links-create.md)


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.