> For the complete documentation index, see [llms.txt](https://docs.thewalletcrew.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.thewalletcrew.io/guides-enrolment/enrolment/download-pages.md).

# Download pages

Download pages are hosted pass-delivery pages. They let customers save Apple Wallet or Google Wallet passes without completing an enrolment form.

<details>

<summary><strong>Real-world examples</strong></summary>

* A loyalty email links to one existing customer card.
* A booking confirmation displays every ticket in one order.
* An account area lists a customer’s active cards and tickets.

</details>

### When to use a download page

Use a download page when the pass already exists. The delivery URL resolves the pass, then shows the relevant wallet action.

Use an [Enrolment form](/guides-enrolment/enrolment/enrolment-form.md) when registration, identity checks, or consent collection must happen first.

Use [On your website](/guides-enrolment/enrolment/on-your-website.md) to embed an Add to Wallet button in an existing web experience. Use [On your mobile app](/guides-enrolment/enrolment/readme-1.md) for a native app flow.

### Configure a download page

Configure download pages in **Wallet → Download pages**. Each page needs a unique URL slug and a page type.

Use separate slugs for separate delivery journeys. For example, use `loyalty` for cards and `tickets` for event passes.

#### Choose the page type

| Page type   | Configuration key | Use when                                  |
| ----------- | ----------------- | ----------------------------------------- |
| Single pass | `pass`            | One delivery URL resolves one pass.       |
| Pass list   | `passList`        | One delivery URL resolves several passes. |

A single-pass page displays wallet actions for the resolved pass. A pass-list page lets customers select matching passes.

#### Configure a single-pass page

Use a `pass` page where the URL resolves exactly one pass.

| Property            | Default | Purpose                                                                      |
| ------------------- | ------- | ---------------------------------------------------------------------------- |
| `autoDownloadPass`  | `false` | Downloads the pass file automatically. This suits mobile deep-link journeys. |
| `passCreation.flow` | —       | Runs when no pass exists. The flow must contain a `Pass` element.            |

Without `passCreation.flow`, a missing pass produces an error.

#### Configure a pass-list page

Use a `passList` page when the URL can resolve several passes. A booking with several tickets is a common example.

| Property                 | Default | Purpose                                             |
| ------------------------ | ------- | --------------------------------------------------- |
| `allowDownloadAllPasses` | `true`  | Displays an action to download every resolved pass. |
| `showInactivePasses`     | `false` | Lists inactive passes without allowing download.    |

#### Apply shared settings

Both page types support these settings.

| Property                         | Purpose                                                                             |
| -------------------------------- | ----------------------------------------------------------------------------------- |
| `headerImage`                    | Displays an image at the top of the page. Use an absolute URL or a `/public/` path. |
| `theme`                          | Overrides the page theme.                                                           |
| `internationalization.resources` | Defines translated string resources, such as `/locales/fields`.                     |
| `errorLayoutName`                | Sends unrecoverable errors to another page slug.                                    |
| `requireValidRedirectId`         | Only accepts a known platform redirect when set to `true`.                          |

{% hint style="info" %}
Set `requireValidRedirectId` to `true` when approved platform redirects must control access. Its default is `false`.
{% endhint %}

### Build a delivery URL

A delivery URL opens a hosted download page. Customers use this page to save a pass to Apple Wallet or Google Wallet.

Use delivery URLs in email, SMS messages, QR codes, and campaign landing pages. Choose the lookup method based on the data available when the link is generated.

Choose the lookup method before building the URL. First, decide whether the link resolves one known pass or a customer record. Then assess whether the identifier is opaque, predictable, or sensitive. Finally, confirm where the URL is generated and which connector handles it.

Use a pass ID when the exact platform pass is known. Use an external ID when a business-owned identifier must resolve a pass or pass list. Use an authentication token when a backend creates a secure, recipient-specific link.

Every delivery URL has this base structure:

`https://{host}/{tenant}/{layout}?{lookup parameter}`

* **`{host}`** is a custom domain or `app.neostore.cloud`.
* **`{tenant}`** is the tenant identifier.
* **`{layout}`** is the configured download-page slug.
* **`{lookup parameter}`** identifies the pass or customer.

The layout controls the page after the pass is found. It can show one pass, a pass list, or a registration flow.

<details>

<summary><strong>Real-world examples</strong></summary>

* A loyalty email resolves one customer card with a signed CRM identifier.
* A QR code opens every ticket linked to one booking identifier.
* A campaign link uses an authentication token for each recipient.

</details>

{% tabs %}
{% tab title="Pass ID" %}
Use a pass ID when the platform-assigned pass ID is already available. This opaque value identifies one known pass. It does not need a signature.

This suits customer communications after pass creation. Store the pass ID when the pass is created. Then add it to the delivery URL.
{% endtab %}

{% tab title="External ID" %}
Use an external ID when a stable, business-owned identifier is available. The identifier key is free-form. Common keys include `y2.customerId`, `comarch.customerId`, and `shopify.orderId`.

Use the same key and value stored on the pass. The security method depends on the identifier and connector. An external ID can be protected with an HMAC signature or by including a secret in the delivery URL.

For an HMAC-protected lookup, add the signature as the matching `.hmac` parameter:

`id.y2.customerId={customerId}&id.y2.customerId.hmac={hmac}`

Use HMAC-SHA256 with the tenant secret. Tenant secrets are available in **Settings → API keys & secrets**. Two rotating secrets are accepted. This supports secret rotation without delivery downtime.

{% hint style="warning" %}
Do not expose a predictable identifier without protection. Customer and loyalty card numbers can be enumerated to access other passes.
{% endhint %}
{% endtab %}

{% tab title="Authentication token" %}
Use an authentication token when a backend creates a signed link for each recipient. The token identifies the customer before the download page opens.

Generate the JWT on a server with the token API. The API key requires the `AuthenticationToken.Write` scope. The response returns one JWT per claim set. Add that JWT as the `neo.authToken` delivery URL parameter.

Tokens are valid for 10 years by default. Set `validityDuration` to shorten this period. For example, `1.00:00:00` creates a one-day validity period.

{% hint style="warning" %}
Generate tokens on a server only. Never expose an API key or token-generation logic in browser code or email templates.
{% endhint %}
{% endtab %}
{% endtabs %}

#### Add campaign tracking

Add `neo.src` to record how a customer reached the download page. Its format is `tags|medium|origin`.

* **tags** are comma-separated categories, such as `email-campaign,loyalty`.
* **medium** is a channel, such as `email`, `sms`, or `qr`.
* **origin** is the referring source. The HTTP `Referer` header is used when omitted.

For example, a loyalty email can use `neo.src=email-campaign,loyalty|email|crm`.

### Validate the delivery flow

Test each page with a delivery URL that targets known data.

1. Confirm that a single-pass page displays the expected pass.
2. Confirm that a pass-list page returns every expected pass.
3. Confirm that inactive passes follow the chosen display setting.
4. Confirm that an altered identifier or signature does not resolve a pass.

### Choose the right delivery channel

Download pages host the pass-delivery experience. Other channels control where that experience starts.

* [Enrolment form](/guides-enrolment/enrolment/enrolment-form.md) — capture data before issuing a pass.
* [On your website](/guides-enrolment/enrolment/on-your-website.md) — add wallet actions to an existing website.
* [Via Email](/guides-enrolment/enrolment/via-email.md) — send secure pass links to existing customers.
* [On your mobile app](/guides-enrolment/enrolment/readme-1.md) — launch native wallet installation from an app.

### FAQ

<details>

<summary><strong>When should a pass-list page be used?</strong></summary>

Use a `passList` page when one delivery URL can resolve several passes. Booking confirmations and account areas are common examples.

</details>

<details>

<summary><strong>Can one brand use several download pages?</strong></summary>

Yes. Multiple pages can use the same type. Give each page a distinct slug for its delivery journey.

</details>

<details>

<summary><strong>Can a download page register a customer?</strong></summary>

No. Use an [Enrolment form](/guides-enrolment/enrolment/enrolment-form.md) when customer identity must be captured before pass issuance.

</details>

<details>

<summary><strong>Which lookup method should be used?</strong></summary>

Use a pass ID when the exact pass is known. Use a signed external identifier for stable business identifiers. Use an authentication token when a backend creates one secure link per recipient.

</details>

<details>

<summary><strong>Must external identifiers be signed?</strong></summary>

Sign predictable identifiers with HMAC-SHA256. Opaque platform pass IDs do not require a signature.

</details>


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.thewalletcrew.io/guides-enrolment/enrolment/download-pages.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
