> ## 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.

# Landing pages and custom domains

> Brand the Redemption Link landing page with your Workspace Branding, set your legal links, choose a Landing Look, turn on bot protection and serve it on your own domain.

When an end customer opens a [Redemption Link](https://docs-consumer.voucher.allride.io/consumer/redemption-links.md), AllRide renders a landing page for you: your branding, the voucher sets the link allows, a search over providers and, after redeeming, the issued code or link. You configure the page once for your whole partner through **Workspace Branding**; every link uses it. The page is available in German and English.

## Branding

The landing page takes its look from your Workspace Branding, the same branding that styles your dashboards. You edit it in the consumer dashboard or with the API:

* [Get workspace branding](https://docs-consumer.voucher.allride.io/api-reference/partner-workspace-branding-get.md) is readable by every member of your partner and by every API key, without a permission.
* [Replace workspace branding](https://docs-consumer.voucher.allride.io/api-reference/partner-workspace-branding-replace.md) (`PUT /partner/v1/branding/workspace`) needs `manage-workspace-branding`, which you can delegate to an API key. It replaces the whole branding document, so send every field you want to keep.

Workspace Branding needs no approval by AllRide. Changes reach open landing pages within 60 seconds.

| Part | Fields | Notes |
| - | - | - |
| Colours | `primaryColor`, `secondaryColor`, `backgroundColor`, `surfaceColor`, `textColor`, `accentColor`, `buttonColor`, `buttonTextColor`, `buttonBorderColor` | `#rrggbb`. Colour pairs must reach WCAG AA contrast, otherwise the save fails with [`insufficient-contrast`](https://docs-consumer.voucher.allride.io/errors/catalog#insufficient-contrast) |
| Images | `logoAssetId`, `logoDarkAssetId`, `iconAssetId`, `heroImageAssetId`, `faviconAssetId`, `emailLogoAssetId` | Upload images first as brand assets ([Create a brand asset](https://docs-consumer.voucher.allride.io/api-reference/partner-brand-assets-create.md), then [Complete an upload](https://docs-consumer.voucher.allride.io/api-reference/partner-brand-assets-complete.md)) |
| Typography and shape | `fontFamily`, `cornerRadius` | |
| Landing page | `landing` | The landing block below; only partners with the consumer role can send it |

### The `landing` block

| Field | Type | What it does |
| - | - | - |
| `title` | Localised text, up to 80 characters | Main heading. Without it the page shows "Your vouchers from" followed by your partner name |
| `intro` | Localised restricted Markdown, up to 1,000 characters | Introduction below the heading |
| `termsUrl` | https URL, optional | Your terms for the voucher programme |
| `privacyUrl` | https URL | Your privacy policy. **Required before you can create Redemption Links** |
| `imprintUrl` | https URL | Your imprint (Impressum). **Required before you can create Redemption Links** |
| `supportEmail`, `supportUrl` | Email, https URL, optional | Shown as help links on the page and in every error or unavailable state |
| `footerText` | Localised text, up to 300 characters | Plain text in the footer |
| `showProviderSearch` | Boolean, default `true` | Shows the search field when the link offers at least two providers; a link that offers one provider never shows it |
| `look` | `vibrant`, `soft`, `bold` or `clean` | The Landing Look, default `vibrant` |
| `botProtection` | `off` or `turnstile` | Bot check on the page, default `off` |

Localised fields are objects with a `de` and an `en` text. Include at least your partner's default locale; add both so that German and English visitors see your own words.

### Landing Look

The Landing Look decides how colourful the page is. AllRide derives the page colours from your branding for the Look you pick; colours you set yourself are used unchanged. Layout, content and order are the same in every Look.

| Look | Character |
| - | - |
| `vibrant` (default) | Gradients and decorative shapes in your brand colours |
| `soft` | Pastel tints of your colours |
| `bold` | Saturated, solid colour blocks |
| `clean` | Restrained and lightly tinted, for conservative brands |

The Look applies only to landing pages. It does not change your dashboards or the generated OTP email.

### Bot protection (Cloudflare Turnstile)

Bot protection is off by default. Turn it on with `landing.botProtection: "turnstile"` if your links are shared widely, for example anonymous links in a newsletter.

* **`off`**: no security check runs on the page. Link limits, entity limits and the [Email OTP Gate](https://docs-consumer.voucher.allride.io/consumer/email-otp-links.md) still apply.
* **`turnstile`**: the page runs Cloudflare Turnstile before an end customer requests an OTP email and before they redeem, and again when they enter a wrong code more than once. Most visitors never see a challenge; Turnstile asks for an interaction only when it is unsure.

The setting applies to every Redemption Link of your partner and takes effect on the next page load. With Turnstile on, end customers who block `challenges.cloudflare.com` cannot redeem, and the page tells them so.

### Example

```bash theme={null}
curl -X PUT "$VOUCHER_API_BASE_URL/partner/v1/branding/workspace" \
  -H "Authorization: Bearer $VOUCHER_API_KEY" \
  -H "Content-Type: application/json" \
  -d @branding.json
```

```json theme={null}
{
  "primaryColor": "#0b6e4f",
  "secondaryColor": null,
  "backgroundColor": "#ffffff",
  "surfaceColor": "#f5f5f5",
  "textColor": "#1a1a1a",
  "accentColor": null,
  "buttonColor": "#0b6e4f",
  "buttonTextColor": "#ffffff",
  "buttonBorderColor": null,
  "logoAssetId": 3095,
  "logoDarkAssetId": null,
  "iconAssetId": null,
  "heroImageAssetId": null,
  "faviconAssetId": null,
  "emailLogoAssetId": null,
  "fontFamily": "source-sans-3",
  "cornerRadius": "md",
  "extensions": null,
  "landing": {
    "title": { "de": "Ihre Mobilitätsgutscheine", "en": "Your mobility vouchers" },
    "intro": { "de": "Wählen Sie einen Anbieter.", "en": "Choose a provider." },
    "termsUrl": "https://www.example-transit.example.com/vouchers/terms",
    "privacyUrl": "https://www.example-transit.example.com/privacy",
    "imprintUrl": "https://www.example-transit.example.com/imprint",
    "supportEmail": "vouchers@example.com",
    "supportUrl": null,
    "footerText": null,
    "showProviderSearch": true,
    "look": "vibrant",
    "botProtection": "off"
  }
}
```

### Content rules

Every text, Markdown and URL value is checked when you save. A value that breaks a content rule (hidden characters, HTML or scripts, encoded data, look-alike brand names, unsafe links, requests for passwords or payment details) is refused with [`content-blocked`](https://docs-consumer.voucher.allride.io/errors/catalog#content-blocked); `more.validationErrors` names each field and the reason. Markdown supports paragraphs, bold, italic, lists, headings level 3 and 4 and https links.

## Terms and legal links

The page footer shows your legal links from the `landing` block:

| Footer link | Field | Required |
| - | - | - |
| Terms and conditions | `landing.termsUrl` | No |
| Privacy | `landing.privacyUrl` | Yes |
| Imprint | `landing.imprintUrl` | Yes |
| Help and email | `landing.supportUrl`, `landing.supportEmail` | No |

Two rules keep the legal links in place:

* You cannot create or reactivate a Redemption Link while `privacyUrl` or `imprintUrl` is missing: the request fails with 422 [`landing-legal-urls-missing`](https://docs-consumer.voucher.allride.io/errors/catalog#landing-legal-urls-missing).
* You cannot remove `privacyUrl` or `imprintUrl` (or send `landing: null`) while any of your links is not revoked, including exhausted and expired links, because their pages are still shown. The save fails with 409 [`landing-legal-urls-required`](https://docs-consumer.voucher.allride.io/errors/catalog#landing-legal-urls-required) and `more.nonRevokedLinkCount`. Revoke the links first.

Provider and voucher terms come from the provider's content. The page first lists every provider the link offers; an end customer expands a provider to see its voucher sets and opens a voucher set's details in a dialog, which shows the voucher set's own voucher terms. App Store and Google Play links and the provider's terms, privacy and website pages belong to the provider and appear at the top of every voucher set's details dialog and next to the issued voucher (also for vouchers issued before the provider changed them), not in the provider list. Every voucher set's button reads "Redeem" ("Einlösen"). A link that offers only one provider shows that provider and its voucher sets straight away, without the provider list and without the search field. Before redeeming, the page states that the end customer accepts the voucher terms of the provider and, when you set `termsUrl`, your terms as well. All partner links open in a new tab.

## Custom domains for landing pages

By default, links point to `https://redeem.voucher.allride.io/r/<token>`. To use your own host name, for example `vouchers.example-transit.example.com`, add a Custom Domain:

1. Add the domain in the developer dashboard ([Custom domains](https://consumer-developers.voucher.allride.io/go/custom-domains)) or with [Add a custom domain](https://docs-consumer.voucher.allride.io/api-reference/partner-custom-domains-create.md) (`manage-domains`, delegable to API keys). Only subdomains work, not the apex of your domain.
2. Create the DNS records the domain shows: a `CNAME` to `customers.voucher.allride.io` plus the ownership and certificate validation `TXT` records.
3. Wait until the domain is `active`. [Re-check a custom domain](https://docs-consumer.voucher.allride.io/api-reference/partner-custom-domains-refresh.md) asks for an immediate check.

A link uses its own `customDomainId` when that domain is `active`, otherwise your default landing domain (`settings.defaultLandingDomainId` of your partner, set in the dashboard) when it is `active`, otherwise `redeem.voucher.allride.io`. When you delete a domain, links that used it fall back to the next host in that order and the old host name stops serving pages.

Custom Domains serve only landing pages; your dashboards always run on AllRide host names. The full setup, statuses and troubleshooting are in [Custom domains](https://docs-consumer.voucher.allride.io/workspace/custom-domains.md).

## Embedding

Landing pages cannot be embedded in an iframe: they send `frame-ancestors 'none'` and `X-Frame-Options: DENY`. To show a link inside your app, open it top-level, in an in-app browser or in a WebView; all of these work.

The page language follows the `lang` query parameter (`?lang=en` or `?lang=de`), then the visitor's browser language, then your partner's default locale. Append `?lang=en` to a link URL if you know your customer's language. End customers can switch the language on the page.

## Related

* [Redemption links](https://docs-consumer.voucher.allride.io/consumer/redemption-links.md)
* [Email OTP links](https://docs-consumer.voucher.allride.io/consumer/email-otp-links.md)
* [Custom domains](https://docs-consumer.voucher.allride.io/workspace/custom-domains.md)
* [Get workspace branding](https://docs-consumer.voucher.allride.io/api-reference/partner-workspace-branding-get.md)
* [Replace workspace branding](https://docs-consumer.voucher.allride.io/api-reference/partner-workspace-branding-replace.md)


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