# Start with The Wallet Crew

Start with the main entry points for The Wallet Crew. Learn wallet fundamentals, understand the platform, then move into the right guide.

The Wallet Crew is a wallet pass platform that connects existing business systems — CRM, POS, loyalty engines, ticketing platforms — to Apple Wallet and Google Wallet. It handles pass design, distribution, and lifecycle updates without creating a new data silo. Customer data stays in your source systems; The Wallet Crew reads from them and delivers the wallet experience on top.

### Find what matters

The Wallet Crew documentation covers Apple Wallet and Google Wallet passes from strategy to operations. Start with the guided entry points below to find the right topic, product area, or implementation path faster.

<button type="button" class="button primary" data-action="ask" data-icon="gitbook-assistant">Ask a question…</button>

### Start here

This page is the fastest way to navigate the platform and the documentation. Use the two entry points below to understand wallet basics first, or to get a product overview before moving into a specific workflow.

{% columns %}
{% column %}

<p align="center"><a href="/pages/FNO2cJwShFXSz3nOAjYv"><img src="/files/IbPrt0L3ewz2y6yhjjTZ" alt="Overview illustration of wallet fundamentals across Apple Wallet and Google Wallet pass usage."></a></p>

#### [Learn wallet fundamentals →](/get-started/readme/wallet-fundamentals)

Understand what a pass is, how customers install it, and the core Apple and Google Wallet concepts.
{% endcolumn %}

{% column %}
[![Overview illustration of The Wallet Crew platform across pass design, distribution, and operations.](/files/gcQLuQcV3COGHe7TZn6q)](/get-started/readme/understand-platform)

#### [Understand the platform →](/get-started/readme/understand-platform)

Get the one-page overview of The Wallet Crew, the main use cases, and the core product model.
{% endcolumn %}
{% endcolumns %}

### Browse by topic

Browse by topic when the goal is already clear. Each section groups the core documentation for pass design, enrolment, lifecycle automation, scanning, security, configuration, integrations, monitoring, and developer workflows.

<table data-view="cards"><thead><tr><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4>Design</h4><p>Create pass layouts, assets, and branding rules for Apple Wallet and Google Wallet.</p></td><td><a href="/files/73OldG7RXTN9FvzZban9">/files/73OldG7RXTN9FvzZban9</a></td><td><a href="/spaces/96iMF0cPuLTC7ZRnUWG9">/spaces/96iMF0cPuLTC7ZRnUWG9</a></td></tr><tr><td><h4>Enrolment</h4><p>Set up pass distribution flows and save-to-wallet entry points across channels.</p></td><td><a href="/files/D0kysijcrZuL1yTjHLdD">/files/D0kysijcrZuL1yTjHLdD</a></td><td><a href="/spaces/lFokgwgJiwLXu7G8MVSJ">/spaces/lFokgwgJiwLXu7G8MVSJ</a></td></tr><tr><td><h4>Animate</h4><p>Drive engagement with updates, triggers, and pass lifecycle events.</p></td><td><a href="/files/36yV02UOnTch5fFYD95k">/files/36yV02UOnTch5fFYD95k</a></td><td><a href="/spaces/97ZAXMtqOjhvBBCfpmcE">/spaces/97ZAXMtqOjhvBBCfpmcE</a></td></tr><tr><td><h4>Scan</h4><p>Validate passes at the point of entry or service with reliable scan flows.</p></td><td><a href="/files/P6kRF2D6eM2UTMV3WOCD">/files/P6kRF2D6eM2UTMV3WOCD</a></td><td><a href="/spaces/iqBD4M0nHFMaFeKR75p9">/spaces/iqBD4M0nHFMaFeKR75p9</a></td></tr><tr><td><h4>Security</h4><p>Protect pass data, control access, and reduce fraud risks across workflows.</p></td><td><a href="/files/Qpi8N8jaGlccVpzbwqc7">/files/Qpi8N8jaGlccVpzbwqc7</a></td><td><a href="/spaces/DHEsGlkdBtbDsjoWOBvA">/spaces/DHEsGlkdBtbDsjoWOBvA</a></td></tr><tr><td><h4>Developers</h4><p>Integrate APIs, automate pass operations, and build custom wallet experiences.</p></td><td><a href="/files/v5AwT1r4mZB5Sc0gJ599">/files/v5AwT1r4mZB5Sc0gJ599</a></td><td><a href="/spaces/OnaDC4sjKAx53j0QV843">/spaces/OnaDC4sjKAx53j0QV843</a></td></tr><tr><td><h4>Configuration</h4><p>Manage workspace settings, product options, and operational defaults.</p></td><td><a href="/files/s9rxAemSbsPmCa9nDuc4">/files/s9rxAemSbsPmCa9nDuc4</a></td><td><a href="/spaces/DJrf9G0l7ArnvuwEH0a8">/spaces/DJrf9G0l7ArnvuwEH0a8</a></td></tr><tr><td><h4>Monitor</h4><p>Track delivery, usage, and platform health to operate passes at scale.</p></td><td><a href="/files/qeCd1j4A7qZzaR0fnNtw">/files/qeCd1j4A7qZzaR0fnNtw</a></td><td><a href="/spaces/EsokFUBfsbM9mlwavmMB">/spaces/EsokFUBfsbM9mlwavmMB</a></td></tr><tr><td><h4>Connectors</h4><p>Connect The Wallet Crew with external systems and data sources.</p></td><td><a href="/files/ER2ZcyBdz9K7vJcCTNFX">/files/ER2ZcyBdz9K7vJcCTNFX</a></td><td><a href="/spaces/lP7d71aYydav6e0pRkxc">/spaces/lP7d71aYydav6e0pRkxc</a></td></tr></tbody></table>


# Learn wallet fundamentals

Understand Apple Wallet and Google Wallet basics, plus the pass types you can configure in The Wallet Crew.

<div data-with-frame="true"><figure><img src="/files/8ch9RqPMAjjRqaU6OlXZ" alt="Overview of wallet fundamentals across Apple Wallet and Google Wallet."><figcaption><p>Wallet fundamentals start with the same principle on both platforms: one pass stays easy to save, easy to find, and easy to present.</p></figcaption></figure></div>

Mobile wallets like Apple Wallet and Google Wallet are no longer just digital folders for coupons. They’ve become central to how people organize the essentials of daily life. Customers add passes to their wallet because it keeps the most-used items (loyalty cards, tickets, offers, and more) at their fingertips without digging through emails, apps, or physical cards. Having a pass in the wallet means instant access when it matters: at checkout, at the gate, or at an event entrance, making each experience smoother and faster for customers.

Beyond simple passes, mobile wallets securely store customers’ **bank cards**, enabling contactless payments from a phone or smartwatch, which makes wallet apps a daily habit for purchases, travel, and access. Adding branded passes, such as a rewards card, concert ticket, or store offer, fits naturally into that routine, keeping the Brand visible each time customers open their wallet. Wallets also act as a **single, always-available hub** for personal credentials, where tickets, membership cards, boarding passes, and other passes live side by side, and this frequent, practical usage increases the likelihood that customers keep and engage with the passes a Brand provides, driving repeat interactions and deeper loyalty over time.

### One place for daily credentials

The Apple Wallet app and the Google Wallet app group items customers need in the moment. That includes coupons, loyalty cards, membership cards, event tickets, and more. Customers do not have to search emails or install an app.

<div data-with-frame="true"><figure><img src="/files/e75a9adf7cdd13b6aed313fc20908fedaf1b1086" alt="Apple Wallet and Google Wallet shown as the two main mobile wallet apps used by customers on iOS and Android."><figcaption><p>Mobile wallets are where customers keep their pass day to day.</p></figcaption></figure></div>

### Instant access at checkout or entry

Most Apple Wallet passes and Google Wallet passes are redeemed with a barcode or QR code. Some use NFC when compatible scanning hardware is available. Customers open the pass and present it in seconds.

### Always up to date

A pass is not a static PDF. An Apple Wallet pass and a Google Wallet pass can refresh over time. This matters when points change, balances decrease, or ticket details update.

Updates are part of the core lifecycle. For update mechanisms and delivery constraints, see [Push notifications](/guides-animation/engage-and-animate/automatisation/push-notifications). For identifiers and data model basics, see [Structure](/developers-guides/pass-architecture/structure).

## Pass types you can configure in The Wallet Crew

The Wallet Crew lets Brands create templates for several **Apple Wallet pass** and **Google Wallet pass** types. Each pass type comes with Apple and Google constraints. The template then defines layout, fields, images, and barcode.

When the template choice is unclear, [Pass types and templates](/guides-design/design/readme-1) helps narrow down the right starting point. When the pass type is already known, the relevant section below is the right entry point. Configuration then happens in the Template Designer.

{% hint style="info" %}
Wallet apps can store payment cards for contactless payments (Apple Pay / Google Pay). The Wallet Crew covers wallet passes (loyalty, tickets, offers, gift cards), not payment cards.
{% endhint %}

### Loyalty card

A loyalty card is a loyalty program **Apple Wallet pass** / **Google Wallet pass**. It rewards customers for coming back. It also makes the loyalty program feel tangible.

* **Best for:** points, stamps, tiered membership, and account identification at POS.
* **Key fields:** member ID, barcode/QR, points balance, tier/status, and key links.
* **Typical redemption:** scan at checkout to identify the customer, then update points/tier.

For the Brand, the goal is retention. Brands reward customers who purchase repeatedly. Brands can offer points, discounts, gifts, and other benefits. A loyalty card can also be an entry point to a customer account. This helps centralize data and personalize experiences.

For customers, the value is immediate. They can see their loyalty status and rewards. They do not need to remember a card number or bring plastic.

When the loyalty card is added to Apple Wallet or Google Wallet, it becomes easier to use. Customers can open the wallet app and select the card in seconds. They do not miss reward opportunities because points and perks stay visible on the pass.

<details>

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

* Retail: points balance and tier (Silver/Gold) updated after each purchase.
* QSR: stamp card (buy 8, get 1 free) with progress displayed on the pass.
* Beauty: member ID used at checkout, plus birthday reward shown as a field.

</details>

More details: [Loyalty Card Template Configuration](/guides-design/design/loyalty-card-template-configuration).

### Event ticket

An event ticket is an access-control **Apple Wallet pass** / **Google Wallet pass**. It is built for fast scanning at the entrance. It also makes it easy for attendees to find the right ticket.

* **Best for:** events with controlled entry and a “scan at gate” workflow.
* **Key fields:** event name, date/time, venue, seat/section, gate, barcode/QR.
* **Typical redemption:** scan at the entrance to validate entry and prevent duplicates.

For organizers, dematerializing tickets reduces loss and fraud risks. It speeds up entry because staff can scan a QR or barcode. It also supports last-minute changes. The same installed ticket can be updated when seat, gate, or schedule changes.

For attendees, adding a ticket to wallet is simple. They can add it from an email link, directly from a ticketing website, or by scanning a QR code on-site. At the venue, the ticket is ready to present in a few taps.

<details>

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

* Concert: seat info + QR scanned at the gate, with “doors open” time on the pass.
* Museum: timed entry ticket, where the date/time changes after reschedule.
* Festival: multi-day pass, with the same pass updated each day with new info.

</details>

More details: [Event ticket](/guides-design/design/event-ticket).

### Gift card

A gift card is a stored-value **Apple Wallet pass** / **Google Wallet pass**. It is meant to be redeemed over time. The key requirement is keeping the balance accurate after each redemption, top-up, or refund.

* **Best for:** stored value that decreases over time (balance use, top-ups, refunds).
* **Key fields:** card number, balance + currency, barcode/QR (or NFC), expiry date.
* **Typical redemption:** scan at checkout, apply partial or full amount, then update balance.

For Brands, gift cards generate revenue upfront. Customers often spend more than the card value. Gift cards are also frequently given to someone else. That makes them a strong acquisition channel for new customers.

For customers, a wallet gift card is easier to keep and use. The pass can display the current balance and a scannable barcode or QR code. It also reduces “lost card” scenarios because the gift card stays on the phone.

<details>

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

* Retail: gift card issued with €100, then balance updated after each redemption.
* Hospitality: voucher sold online, used in multiple partial payments on-site.
* Customer care: goodwill credit added as a top-up, then spent over time.

</details>

More details: [Gift card](/guides-design/design/gift-card).

### Offer

An offer is a coupon-style **Apple Wallet pass** / **Google Wallet pass**. It is used for discounts and time-bound incentives. Offers are often redeemed once, then become invalid.

* **Best for:** discounts, promo codes, and short campaigns with clear expiry rules.
* **Key fields:** offer title, expiry date, conditions, barcode/QR or promo code.
* **Typical redemption:** scan in-store or enter the code online, then mark as redeemed.

For Brands, offers are a practical way to drive traffic and conversion. They can also support segmentation. Different offers can be issued to different audiences. An offer can also be stopped or expired without requiring a reinstall.

For customers, wallet offers are easy to retrieve at checkout. The pass can display the expiry date and conditions clearly. It can also present a scannable barcode or a code to enter online.

<details>

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

* Retail: “-20% this weekend” coupon with an expiry date and single-use barcode.
* E-commerce: promo code shown on the pass, redeemed in checkout.
* CRM: win-back offer sent to inactive customers, then marked as redeemed in POS.

</details>

More details: [Offer](/guides-design/design/offer).

### Generic

Generic is the most flexible **Apple Wallet pass** / **Google Wallet pass** type. It fits use cases that do not match a dedicated template. It is a good fit for credentials that must be shown or scanned.

* **Best for:** membership cards, staff badges, warranty cards, pickup credentials, and “other”.
* **Key fields:** a stable identifier, barcode/QR, status, key facts, and support links.
* **Typical redemption:** visual check or scan, depending on the operational workflow.

For Brands, Generic helps when a custom layout is needed. Fields and display order are fully configurable. This is useful for membership cards that are not loyalty programs, staff passes, partner badges, warranty cards, or pickup credentials.

For customers, a Generic pass works like any other pass. It is easy to add, easy to find, and easy to present. It can also be updated when details change.

<details>

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

* Staff badge: employee name + role + QR for door access.
* Warranty card: product serial number + purchase date + support link.
* Click & collect: pickup credential with order ID + barcode for retrieval.

</details>

More details: [Generic](/guides-design/design/generic).

## FAQ

<details>

<summary><strong>Do customers need a mobile app to add a pass?</strong></summary>

No. Customers can add a pass from a Brand website or email. QR codes also work in-store or on-site. If a mobile app exists, an in-app flow can be added later.

</details>

<details>

<summary><strong>Do passes work offline?</strong></summary>

Usually yes for the moment of use. The barcode/QR and the visible fields are stored on the phone. Updates still require connectivity at some point to sync.

</details>

<details>

<summary><strong>What’s the difference between an Offer and a Gift card?</strong></summary>

Offers are for discounts and coupons. Gift cards are for stored value and balance updates. If the value can go down over time, it is almost always a Gift card.

</details>

<details>

<summary><strong>Can a pass be updated after it’s installed?</strong></summary>

Yes. This is one of the main advantages of mobile wallets. The Wallet Crew updates the same installed pass, so customers don’t need to re-add it.

</details>

<details>

<summary><strong>Can multiple pass types be used in one project?</strong></summary>

Yes. Many Brands start with one pass type (often loyalty) and add others later. Pass types can share the same distribution channels and operational setup.

</details>


# Key concepts

Understand the key concepts behind The Wallet Crew: tenant, pass template, pass, and environment.

The Wallet Crew is built around a small set of concepts that appear throughout the platform. Understanding them once makes every other page faster to navigate.

{% hint style="info" %}
Payment cards such as Apple Pay and Google Pay are out of scope here. The Wallet Crew manages wallet passes such as loyalty cards, tickets, offers, and gift cards — not payment instruments.
{% endhint %}

<details>

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

* A retail Brand may run one tenant, one loyalty template, and millions of customer passes.
* A ticketing Brand may use one ticket template per event family, then issue one pass per attendee.
* An international group may keep one tenant per country when teams, credentials, and data must stay separate.

</details>

## Tenant

A tenant is the isolated workspace for one Brand or wallet program inside The Wallet Crew. Everything configured there lives inside that tenant: wallet designs, passes, data, and team access.

A simple way to think about it is a private building, not a shared open space. What exists in one tenant does not mix with another tenant.

Most Brands have one tenant. Some groups run several tenants when separate brands, countries, or programs must stay independent, with their own Apple and Google credentials, their own data, and their own teams.

{% hint style="info" %}
A tenant is not a folder or a sub-account inside a shared workspace. Each tenant is a fully isolated environment. There is no cross-tenant data access by design.
{% endhint %}

## Pass template

A pass template is the model for one kind of wallet pass. It defines which wallet platform is targeted, how the pass looks, which fields appear, which barcode format is used, and how personalisation works.

The easiest analogy is a blueprint. The template defines the rules once, then The Wallet Crew reuses those rules every time a new pass is created from it.

A template is not a pass. It does not belong to one customer. It is the reusable definition behind many passes.

One Brand can use several templates at the same time. A loyalty card, a gift card, and an event ticket each usually need their own template.

## Pass

A pass is one wallet card, ticket, or voucher issued to one customer. It is created from a template and linked to Brand systems, such as a CRM, loyalty engine, POS, or ticketing platform.

If the template is the blueprint, the pass is the finished item in the customer’s wallet. One template can create thousands or millions of individual passes.

Passes move through a lifecycle:

* **Created** — the pass exists on the platform.
* **Installed** — the customer added it to Apple Wallet or Google Wallet.
* **Updated** — the pass content changed, such as a points balance, status, or message.
* **Uninstalled** — the customer removed it from the wallet.

Created and installed are two different moments. A pass can exist before a customer saves it to the wallet.

The Wallet Crew does not store customer personal data by default. Passes are usually linked through stable identifiers, such as a CRM ID or loyalty number, while core customer data stays in Brand systems.

## Environment

Environments separate testing from live operations. In practice, The Wallet Crew provides **QA** for testing and **production** for real customers.

QA is the rehearsal stage. Production is the live stage. QA mirrors production closely so testing reflects real conditions before launch.

These environments are fully isolated. A pass created in QA never appears in production, and production credentials or live data are not shared into QA.

Configuration can be copied between environments when needed. A third environment, **dev**, exists for internal engineering use only and is not accessible to customers.

## What comes next

* To understand what the platform can track after issuance, see [Monitoring](https://docs.thewalletcrew.io/guides-monitoring/).
* To start configuring a first template, see [Card design (colors, images, and fields)](/configure/advanced-configuration/wallet/template-configuration/cards-design-colors-images-and-fields).
* For a deeper technical model, start with [Structure](/developers-guides/pass-architecture/structure) and the [Developers](https://docs.thewalletcrew.io/developers-guides/) area.

## FAQ

<details>

<summary><strong>Can one template create many passes?</strong></summary>

Yes. That is the normal model. A template is reused to issue many individual passes that share the same structure and design.

</details>

<details>

<summary><strong>Can the same customer have several passes?</strong></summary>

Yes. One customer may hold several passes from the same Brand, such as one loyalty card and several event tickets. Each pass still remains its own record.

</details>

<details>

<summary><strong>Why keep QA and production separate?</strong></summary>

Separation reduces risk. Teams can test designs, links, and data flows in QA without affecting live customers or live credentials.

</details>


# Understand the platform

One-page overview of The Wallet Crew platform: what it is, what it does, and how teams use it.

<div data-with-frame="true"><figure><img src="/files/8w41WwRUpcqi86onfEVA" alt="Overview of The Wallet Crew platform for wallet pass design, distribution, and lifecycle operations."><figcaption><p>The Wallet Crew connects pass design, distribution, and lifecycle operations in one platform.</p></figcaption></figure></div>

The Wallet Crew is a white-label platform to **create, distribute, and operate wallet passes**. Brands use it for **loyalty cards, coupons, gift cards, tickets, and membership cards** in **Apple Wallet** and **Google Wallet**. Customers save the pass once, then the same pass stays **up to date over time**.

TWC acts as a bridge between existing business systems and wallet providers — it does not create a new data silo. Customer profiles, loyalty records, tickets, and transactions remain in their source systems. TWC reads from them, transforms the data into wallet-compatible content, and delivers updates when those records change.

TWC is not a self-service-only tool. Expertise and integration design are part of the engagement — each deployment is shaped around specific data models and business processes, with The Wallet Crew team involved throughout.

### What problems it solves

Most wallet projects start with the same friction. Customers need something scannable at checkout or entry. App installs stay low. Plastic cards add cost and logistics.

The Wallet Crew ships pass distribution through web, email, or QR. It then keeps that same installed pass accurate with updates over time. This creates one operating layer across Apple and Google while still following each provider’s rules.

Wallet is also not a “marketing-only” channel. A pass is a **digital credential** that customers can present in the moment, even with poor connectivity. Notifications can help, but the core value is simple: the pass remains available, scannable, and current.

### Who it’s for

The Wallet Crew is designed for business and technical teams. It supports deep configuration when needed, without forcing every stakeholder into the same level of detail.

Marketing and CRM teams get an owned surface on the phone that customers actually keep. Content can be refreshed through pass updates and, when relevant, wallet notifications.

Delivery, product, and operations teams ship faster because a launch does not depend on app adoption. IT, data, and security teams get a connected layer that links passes to CRM, loyalty engine, POS, and ticketing systems, with privacy-first setups by default.

### How it works (high level)

The Wallet Crew follows a simple lifecycle. A team designs a template, distributes an “Add to Wallet” entry point, then pushes updates over time.

1. **Design**: pick a pass type and configure branding, fields, and barcode/QR. Start with [Card design (colors, images, and fields)](/configure/advanced-configuration/wallet/template-configuration/cards-design-colors-images-and-fields).
2. **Connect data**: link each pass to source systems using stable identifiers, so CRM and POS remain the source of truth. See [Structure](/developers-guides/pass-architecture/structure).
3. **Distribute**: ship pass installation from owned channels. Most deployments start with [On your website](/guides-enrolment/enrolment/on-your-website) and [Via Email](/guides-enrolment/enrolment/via-email).
4. **Operate and engage**: update passes, trigger notifications, and measure adoption over time. Start with [Push notifications](/guides-animation/engage-and-animate/automatisation/push-notifications).

### Key capabilities

#### Wallet is reach, not only notifications

A wallet pass is a persistent object on the customer’s phone. It is easy to retrieve and show at the point of sale, at entry gates, or during customer service interactions. This makes wallet a practical channel for operations, not only for campaigns.

Notifications are optional and depend on use case and provider rules. In many programs, the main outcome is simply higher usage because the pass is quick to access and hard to lose.

#### Pass templates for Apple Wallet and Google Wallet

Templates are configured once, and The Wallet Crew generates the right Apple and Google payloads.

Most Brands start with a core set of templates, then expand over time. A common baseline includes [Loyalty Card Template Configuration](/guides-design/design/loyalty-card-template-configuration), [Offer](/guides-design/design/offer), [Gift card](/guides-design/design/gift-card), [Event ticket](/guides-design/design/event-ticket), and [Generic](/guides-design/design/generic).

For multi-language programs, labels and content can be translated per template. See [How to translate a template](/configure/advanced-configuration/wallet/template-configuration/how-to-translate-a-template).

#### Distribution without forcing a mobile app

Customers can add a pass without a mobile app, which is usually the biggest adoption lever. Most deployments start with web and email, then expand to QR codes in-store or on-site.

Common distribution entry points include [On your website](/guides-enrolment/enrolment/on-your-website), [Via Email](/guides-enrolment/enrolment/via-email), and, when an app exists, [On your mobile app](/guides-enrolment/enrolment/readme-1).

#### Updates, notifications, and location-based experiences

Wallet passes are meant to evolve, so the same installed pass can change after it’s saved.

Typical update scenarios include points and tier refresh after purchase, coupon state changes after redemption, gift card balance updates, and ticket changes.

Start with [Push notifications](/guides-animation/engage-and-animate/automatisation/push-notifications), then see [Geolocated Notifications](/guides-animation/engage-and-animate/geolocated-notifications).

Even without notifications, updates still matter. They keep the pass trustworthy by keeping balances, tiers, validity, and ticket states accurate when the customer opens the pass.

#### Integrations and APIs

The Wallet Crew sits between distribution channels and source systems.

Teams integrate through built-in connectors, including CRM, POS, and marketing automation tools. The API can also be used for issuance, updates, and lookups. Start with [API reference](https://docs.thewalletcrew.io/api-reference/).

#### Operations and in-store/on-site usage

Operating wallet at scale needs targeting and reliable redemption. Metadata can be attached to passes for segmentation, then used to target by store, country, tier, or channel. See [Structure](/developers-guides/pass-architecture/structure).

When staff tooling is needed, operators can use [Pass Scanner](/guides-scan/scan/pass-scanner) to scan and validate passes.

### What it is (and is not)

The Wallet Crew is a platform dedicated to managing the entire lifecycle of wallet passes. It enables you to design, distribute, and update passes while connecting seamlessly to your existing channels and data systems.

It is not a payment solution, all payment transactions continue to operate within Apple Pay and Google Pay. It also does not replace your existing business systems such as CRM, loyalty platforms, POS, or ticketing tools. Those systems remain your source of truth; The Wallet Crew simply extends their data into the wallet experience.

### Privacy and security

The Wallet Crew follows a **privacy-first approach**. Many deployments avoid storing personal data and store **external identifiers** instead. Those identifiers let The Wallet Crew fetch data and render the pass.

For distribution security, see [Wallet card security](/configure/advanced-configuration/wallet/wallet-card-security). It covers signed links, HMAC/JWT, and ID enumeration risks.

### FAQ

<details>

<summary><strong>Do customers need to install a mobile app?</strong></summary>

No. Most Brands start without an app, and customers add passes from web pages, email, or QR codes. When an app exists, an in-app flow can be added later. See [On your mobile app](/guides-enrolment/enrolment/readme-1).

</details>

<details>

<summary><strong>Can Brand-owned Apple and Google issuer accounts be used?</strong></summary>

Yes. Apple and Google require Brand-owned issuer credentials in production, and The Wallet Crew issues passes under the Brand identity.

Start with [Apple & Google wallet](/configure/advanced-configuration/wallet/apple-and-google-wallet).

</details>

<details>

<summary><strong>How do pass updates work after installation?</strong></summary>

Pass data is updated from source systems, and The Wallet Crew pushes the change to Apple and Google. Start with [Push notifications](/guides-animation/engage-and-animate/automatisation/push-notifications). It explains triggers and what customers see.

</details>

<details>

<summary><strong>Do you store personal data?</strong></summary>

It depends on the deployment. Many deployments store only identifiers and operational metadata, while the CRM remains the source of truth for PII.

For the data model, see [Structure](/developers-guides/pass-architecture/structure).

</details>

<details>

<summary><strong>Can we scan and validate passes in-store or at event entry?</strong></summary>

Yes. Passes can be scanned using barcode or QR readers. For a dedicated operator experience, use [Pass Scanner](/guides-scan/scan/pass-scanner).

</details>


# Implementation roadmap

Typical sequence to launch a wallet program with The Wallet Crew, from contract signature to go-live, with a lot-based delivery approach.

This roadmap describes the typical sequence to launch a wallet program with The Wallet Crew. It starts at contract signature and ends at go‑live, with an agile delivery approach and small, testable increments.

<details>

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

* A retail Brand launches a loyalty card and focuses first on POS scanning, then adds CRM campaigns.
* A venue integrates ticketing first to ensure entry works, then adds post-event engagement.
* A Brand replaces plastic membership cards with a digital pass, using a phased rollout per region.
* A Brand starts with a single “core” template, then adds seasonal or event-specific templates.

</details>

## Roadmap overview

Most wallet projects succeed when operations lead the design. The pass must work at the point of sale or at the gate before it becomes a marketing channel. The Wallet Crew therefore prioritizes early validation of the end‑to‑end chain: source systems → pass data → distribution → wallet installation → redemption.

The sequence below is the default. Some steps can overlap. The lot-based delivery approach stays the same: ship small increments, validate quickly on real devices, then expand scope.

## Project phases (contract → go-live)

{% stepper %}
{% step %}

#### 1) Contract and kickoff

This phase aligns on scope, stakeholders, and constraints. It sets the working cadence and defines what “done” means for the first release.

Typical outputs include a project calendar, a list of owners, and a first go‑live target.
{% endstep %}

{% step %}

#### 2) Requirements collection (atelier)

The Wallet Crew runs a dedicated atelier to capture Brand needs and constraints. It is a working session, not a presentation. The goal is to converge on a first “minimal viable” wallet experience.

The atelier usually covers pass use case, distribution channels, redemption/scanning constraints, required data fields, consent/GDPR expectations, and reporting needs.
{% endstep %}

{% step %}

#### 3) Technical setup (tenant + wallets + custom domain)

This phase makes the platform ready for secure testing and future production issuance.

It typically includes:

* Tenant provisioning (staging and, when relevant, production).
* Apple Wallet configuration (certificates, push keys, signing identity).
* Google Wallet configuration (issuer account access, service account / API credentials).
* Custom domain setup for branded links and hosted pages, when required.

Related docs:

* Wallet provider setup: [Apple & Google Wallet](/configure/advanced-configuration/wallet/apple-and-google-wallet)
* Apple certificates: [Apple Wallet certificates](/configure/advanced-configuration/wallet/apple-and-google-wallet/apple-wallet-certificates)
* Google issuer setup: [Google Wallet account](/configure/advanced-configuration/wallet/apple-and-google-wallet/google-wallet-account)
* Custom domain: [Custom domain](/configure/advanced-configuration/platform/custom-domain)
  {% endstep %}

{% step %}

#### 4) IT architecture definition (system-of-record and data ownership)

This phase defines where The Wallet Crew sits in the overall IT landscape. It also clarifies which systems remain the source of truth for each data element displayed on the pass.

The key decision is the data flow: what triggers pass creation, how updates are computed, and how identifiers link a pass to Brand systems over time.

Related docs:

* Data model and identifiers: [Structure](/developers-guides/pass-architecture/structure)
  {% endstep %}

{% step %}

#### 5) Project definition and lot-based delivery (agile increments)

This phase turns the scope into shippable lots. Each lot should be testable without future work. This reduces go‑live risk and avoids “big bang” rollouts.

A common breakdown is:

* Lot 1: one template + one distribution channel + one redemption path.
* Lot 2: updates lifecycle (field refresh, status changes, deactivation rules).
* Lot 3: segmentation, analytics, and operational tooling.
* Lot 4: marketing automation, notifications, and personalization at scale.
  {% endstep %}

{% step %}

#### 6) User experience flow (install → present → update)

This phase defines the customer journey and the operational journey. It includes entry points (“Add to Wallet”), install screens, fallback flows (desktop → QR), and how the pass is retrieved later.

Distribution choices typically map to these docs:

* [Enrolment form](/guides-enrolment/enrolment/enrolment-form)
* [On your website](/guides-enrolment/enrolment/on-your-website)
* [Via Email](/guides-enrolment/enrolment/via-email)
* [On your mobile app](/guides-enrolment/enrolment/readme-1)
  {% endstep %}

{% step %}

#### 7) Pass configuration (templates + fields + barcode)

This phase translates the UX and data model into a pass template configuration for Apple Wallet and Google Wallet. It covers branding assets, field layout, links, and barcode/QR payload.

Template configuration lives under:

* [Template configuration](/configure/advanced-configuration/wallet/template-configuration)
* Design reference: [Card design (colors, images, and fields)](/configure/advanced-configuration/wallet/template-configuration/cards-design-colors-images-and-fields)
  {% endstep %}

{% step %}

#### 8) Connect core tools first (ticketing, POS, CRM/loyalty)

The Wallet Crew recommends connecting the core operational systems before adding marketing layers. Wallet is a credential. It must work reliably where the pass is used.

This phase usually delivers:

* A working creation/update feed from core systems.
* A stable identifier strategy (membership number, ticket ID, gift card code, …).
* A validated redemption flow in real conditions (scanner, POS, entry gate).

Once this is stable, marketing automation can be added without risking operations.
{% endstep %}

{% step %}

#### 9) Add marketing and engagement (optional, after core validation)

This phase adds lifecycle engagement such as wallet notifications, geolocation, and marketing automation connectors. It is easier to iterate once core issuance and redemption are stable.

Entry points:

* Notifications: [Push notifications](/guides-animation/engage-and-animate/automatisation/push-notifications)
* Location triggers: [Geolocated Notifications](/guides-animation/engage-and-animate/geolocated-notifications)
* Marketing connectors: [Marketing automation](/connectors/marketing-automation)
  {% endstep %}

{% step %}

#### 10) Go-live and operations

This phase completes production readiness: monitoring, support runbooks, and controlled rollout. It also defines how changes are shipped after go‑live (template updates, field additions, new lots).

Typical validation includes a production pilot, real-device checks on iOS and Android, and scanning tests in representative environments.
{% endstep %}
{% endstepper %}

## Common deliverables (what “done” looks like)

At go‑live, the minimal expected package usually includes one pass template, one distribution flow, and one operational redemption flow. It also includes a clear update strategy, so the pass remains trustworthy after installation.

As the program scales, deliverables expand to additional templates, segmentation, reporting, and optional engagement features.

## FAQ

<details>

<summary><strong>Can the project start before Apple/Google accounts are fully approved?</strong></summary>

Yes, in most cases. Requirements, UX definition, and template design can start immediately. Wallet provider approvals and credentials must be completed before production issuance.

</details>

<details>

<summary><strong>Why does The Wallet Crew recommend connecting core systems before marketing tools?</strong></summary>

Because wallet is used in operational moments. If POS or ticketing redemption is unstable, marketing amplification increases support load. Once core issuance, updates, and redemption are reliable, marketing automation and notifications can be added safely.

</details>

<details>

<summary><strong>Can the scope be limited to a single template for the first release?</strong></summary>

Yes. A single template is often the best first lot. It keeps the data model and governance simple, and it enables faster validation on devices and in stores/venues.

</details>

<details>

<summary><strong>Is a custom domain mandatory?</strong></summary>

No. A custom domain is recommended when branded links and brand-aligned hosted pages are required. Some projects start without it, then add it before go‑live.

</details>

<details>

<summary><strong>What typically causes delays?</strong></summary>

Delays usually come from external dependencies: wallet provider approvals, DNS changes for custom domains, security reviews, and clarifying data ownership between systems. Keeping lots small reduces the impact of these delays.

</details>


# Find your starting point

Choose the right The Wallet Crew entry pages based on role, goal, and level of detail.

Different teams use The Wallet Crew for different reasons. Some need the product model first. Others need data flows, launch sequence, or technical reference. This page points each role to the right first pages.

#### **Marketing & CRM**

Marketing and CRM teams usually arrive asking how the platform works and what it actually does.

The useful first model is simple: design a pass, distribute it, then keep it current after installation. [Understand the platform](/get-started/readme/understand-platform) gives that lifecycle in one page. [Learn wallet fundamentals](/get-started/readme/wallet-fundamentals) explains how passes behave in Apple Wallet and Google Wallet. When the goal shifts to acquisition and conversion, [Enrolment](https://docs.thewalletcrew.io/guides-enrolment/) is the right hub for website, email, and in-app entry points.

#### **IT / Data / Security**

IT, data, and security teams usually arrive asking how data is synced and which system owns what.

The main question is usually data flow, not only integration. The Wallet Crew often stores identifiers and operational metadata, while core systems stay the source of truth. Start with [Understand the platform](/get-started/readme/understand-platform), especially the “How it works” section, to place the platform in the stack. Then move to [Structure](/developers-guides/pass-architecture/structure) for identifiers, ownership, and pass architecture, and use [Connectors](https://docs.thewalletcrew.io/connectors/) to review supported integration patterns.

#### **Developer**

Developers usually arrive asking where the technical reference starts and how authentication works.

The shortest route is the [Developers](https://docs.thewalletcrew.io/developers-guides/) area, which groups pass architecture and API key setup. The [API reference](https://docs.thewalletcrew.io/api-reference/) is the next stop for endpoints, payloads, and response shapes. Use [Connectors](https://docs.thewalletcrew.io/connectors/) when the project depends on an existing integration instead of a custom flow.

#### **Project manager**

Project managers usually arrive asking how The Wallet Crew fits into the existing stack and what happens first.

The fastest orientation starts with the [Implementation Roadmap](/get-started/readme/implementation-roadmap), which lays out the common launch sequence from kickoff to go-live. It shows when data ownership, distribution, and operational validation should be decided. [Understand the platform](/get-started/readme/understand-platform) explains where The Wallet Crew sits between source systems and wallet channels. [Connectors](https://docs.thewalletcrew.io/connectors/) helps map the project against existing CRM, POS, ticketing, and marketing tools.

#### **Stakeholder / Executive**

Stakeholders and executives usually arrive asking whether the platform is documented clearly enough to support a decision.

The quickest confidence check starts with [Understand the platform](/get-started/readme/understand-platform). It gives a short, factual view of the product model, scope, and operating principles. [Implementation Roadmap](/get-started/readme/implementation-roadmap) shows that delivery follows a defined sequence, with clear phases and validation points. Together, those pages show how The Wallet Crew fits into a real programme without going into technical detail.


# Guides

Browse The Wallet Crew guides for Apple Wallet and Google Wallet pass design, configuration, distribution, geolocated engagement, monitoring, and scan validation.

The Wallet Crew guides cover the full lifecycle of an Apple Wallet and Google Wallet program. They help Brands move from pass design and configuration to distribution, geolocated engagement, monitoring, and scan validation.

<details>

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

* A retail Brand configures a loyalty card, publishes an enrolment form, then triggers geolocated notifications near stores.
* A ticketing Brand configures wallet credentials, distributes tickets by email, then validates entry with real-time scans.
* A gift card program synchronizes balances, monitors pass activity, and keeps the same installed pass current over time.

</details>

### Browse the core guides

Each guide below covers one operational area. Start with Configuration when the wallet project is still being set up. Start with Design or Enrolment when the technical foundation already exists.

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><h4><i class="fa-paintbrush" style="color:$primary;">:paintbrush:</i></h4></td><td><h4>Design</h4></td><td>Define how the pass looks and behaves in Apple Wallet and Google Wallet. Structure the layout, branding, fields, links, and barcode without moving core business data out of existing systems.</td><td><a href="/spaces/96iMF0cPuLTC7ZRnUWG9">/spaces/96iMF0cPuLTC7ZRnUWG9</a></td><td><a href="/files/qdIqE5TBBPY4EdPrF2PP">/files/qdIqE5TBBPY4EdPrF2PP</a></td></tr><tr><td><h4><i class="fa-gear" style="color:$primary;">:gear:</i></h4></td><td><h4>Configuration</h4></td><td>Prepare the wallet foundation before launch. Configure issuer accounts, certificates, custom domains, template settings, and operational defaults for secure production use.</td><td><a href="/spaces/DJrf9G0l7ArnvuwEH0a8">/spaces/DJrf9G0l7ArnvuwEH0a8</a></td><td><a href="/files/s9rxAemSbsPmCa9nDuc4">/files/s9rxAemSbsPmCa9nDuc4</a></td></tr><tr><td><h4><i class="fa-layer-plus" style="color:$primary;">:layer-plus:</i></h4></td><td><h4>Enrolment</h4></td><td>Control how customers add a pass to their phone. Compare hosted forms, website embeds, email flows, QR codes, and in-app entry points to improve conversion and data quality.</td><td><a href="/spaces/lFokgwgJiwLXu7G8MVSJ">/spaces/lFokgwgJiwLXu7G8MVSJ</a></td><td><a href="/files/cZKS1reW7O3wVarjo9zU">/files/cZKS1reW7O3wVarjo9zU</a></td></tr></tbody></table>

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="files"></th></tr></thead><tbody><tr><td><h4><i class="fa-bell-ring" style="color:$primary;">:bell-ring:</i></h4></td><td><h4>Engage &#x26; animate</h4></td><td>Keep the installed pass useful after it is saved. Use pass updates, push notifications, geolocated alerts near stores or venues, and privilege logic tied to time, balance, or counters.</td><td><a href="/spaces/97ZAXMtqOjhvBBCfpmcE">/spaces/97ZAXMtqOjhvBBCfpmcE</a></td><td><a href="/files/Sl5PoYQ2k0d6X4fhFwq1">/files/Sl5PoYQ2k0d6X4fhFwq1</a></td></tr><tr><td><h4><i class="fa-chart-line" style="color:$primary;">:chart-line:</i></h4></td><td><h4>Monitoring</h4></td><td>Track what happens after issuance. Review installation status, pass activity, privilege usage, and synchronization signals needed to operate wallet programs at scale.</td><td><a href="/spaces/EsokFUBfsbM9mlwavmMB">/spaces/EsokFUBfsbM9mlwavmMB</a></td><td><a href="/files/qCOJ673uQWwaBH2rpMJ1">/files/qCOJ673uQWwaBH2rpMJ1</a></td></tr><tr><td><h4><i class="fa-barcode-read" style="color:$primary;">:barcode-read:</i></h4></td><td><h4>Scan &#x26; validate</h4></td><td>Validate passes at a gate, POS, counter, or service desk. Use real-time scans to read the pass, display the right privileges, and prevent duplicate or invalid redemption.</td><td><a href="/spaces/iqBD4M0nHFMaFeKR75p9">/spaces/iqBD4M0nHFMaFeKR75p9</a></td><td><a href="/files/P0nzScB9jPYqm12wYMmw">/files/P0nzScB9jPYqm12wYMmw</a></td></tr></tbody></table>

### How to use this page

This page works as the shortest route into the operational guides. It is useful when the goal is already known, such as configuring Apple Wallet certificates, launching an Add to Wallet flow, enabling location-based notifications, or validating passes in store or at event entry.

### FAQ

<details>

<summary><strong>Where should a new wallet project start?</strong></summary>

Most projects start with Configuration, then move to Design and Enrolment. That sequence reduces launch risk because wallet credentials, domains, and provider access are validated before distribution starts.

</details>

<details>

<summary><strong>Which guide covers location-based wallet experiences?</strong></summary>

Use Engage & animate for geolocated notifications and other post-install triggers. That area also covers push notifications and privilege logic that changes over time.

</details>

<details>

<summary><strong>Which guide covers in-store or event validation?</strong></summary>

Use Scan & validate when the pass must be checked at a door, POS, counter, or service point. That guide covers staff-facing scan flows and real-time redemption control.

</details>


# Design Guides

Five sections covering the full lifecycle of a wallet pass program, written for the people who run it day to day.

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><h4><i class="fa-house-crack" style="color:$primary;">:house-crack:</i></h4></td><td><h3>General</h3></td><td><p>Understand how pass types andLoyalty templates work together. The starting point before configuring any pass in The Wallet Crew.</p><p><br></p></td><td><a href="/pages/1Y9SQXpCfnWP5gAnv8m3">/pages/1Y9SQXpCfnWP5gAnv8m3</a></td><td><a href="/files/RD44AcRBINzUGeJvsMcc">/files/RD44AcRBINzUGeJvsMcc</a></td></tr><tr><td><h4><i class="fa-user-group-crown" style="color:$primary;">:user-group-crown:</i></h4></td><td><h3>Loyalty card</h3></td><td>Configure a loyalty card template: member ID, tier, points, barcode. Designed for programs that update over the customer lifecycle.</td><td><a href="/pages/1GWExrYIqrVx4rDGznyu">/pages/1GWExrYIqrVx4rDGznyu</a></td><td><a href="/files/CqC6grBjKa5xbaclV6Em">/files/CqC6grBjKa5xbaclV6Em</a></td></tr><tr><td><h4><i class="fa-tickets-perforated" style="color:$primary;">:tickets-perforated:</i></h4></td><td><h3>Event ticket</h3></td><td>Set up an event ticket pass: venue, date, seat, gate, and scannable barcode. Supports real-time updates for schedule changes.</td><td><a href="/pages/n9Zihv9BSO1ZtnDvEc8Q">/pages/n9Zihv9BSO1ZtnDvEc8Q</a></td><td><a href="/files/hZuZXywBplqNZZ0x1He2">/files/hZuZXywBplqNZZ0x1He2</a></td></tr></tbody></table>

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td><h4><i class="fa-hand-holding-heart" style="color:$primary;">:hand-holding-heart:</i></h4></td><td><h3>Gift card</h3></td><td>Set up a time-bound coupon or promotion pass: expiry date, conditions, and a redemption code. Typically single-use, with status updates on redemption.</td><td><a href="/pages/pXFx6BySfF0t4YT8jiV3">/pages/pXFx6BySfF0t4YT8jiV3</a></td><td><a href="/files/RD44AcRBINzUGeJvsMcc">/files/RD44AcRBINzUGeJvsMcc</a></td></tr><tr><td><h4><i class="fa-tags" style="color:$primary;">:tags:</i></h4></td><td><h3>Offer</h3></td><td>Set up a time-bound coupon or promotion pass: expiry date, conditions, and a redemption code. Typically single-use, with status updates on redemption.</td><td><a href="/pages/c7sqOTHuDOx7FTEIf5fR">/pages/c7sqOTHuDOx7FTEIf5fR</a></td><td><a href="/files/ESVdgr7QmI0sav0hH4lr">/files/ESVdgr7QmI0sav0hH4lr</a></td></tr><tr><td><i class="fa-draw-circle" style="color:$tint;">:draw-circle:</i></td><td><h3>Generic</h3></td><td><p>A flexible pass for cases that don't fit standard types: staff badges, membership cards, warranty cards, or pickup credentials.</p><p><br></p></td><td><a href="/pages/TgdsO8PUTUHlpoxB0u5M">/pages/TgdsO8PUTUHlpoxB0u5M</a></td><td><a href="/files/oowYwZaATTjLycodgPzA">/files/oowYwZaATTjLycodgPzA</a></td></tr></tbody></table>

#### **Design**

Every wallet pass starts with a choice: which pass type fits your use case, and how should it be configured? The Design section walks through the building blocks available in The Wallet Crew, from foundational concepts to ready-to-use templates for common scenarios.

**Pass Types & Templates** is the starting point — it explains how types and templates work together before you configure anything. From there, dedicated guides cover each major pass type: **Loyalty Card** templates handle member ID, tier, points, and barcode for programs that evolve over a customer's lifecycle. **Event Ticket** templates manage venue, date, seat, and gate information, with support for real-time updates when schedules change. **Gift Card** and **Offer** templates cover time-bound promotions with expiry dates, redemption conditions, and status updates once used. For everything else — staff badges, membership cards, warranty cards, pickup credentials — the **Generic** pass type offers a flexible structure that adapts to non-standard cases.

Together, these guides give you the full toolkit to design a pass that matches your business model, whether you're building loyalty programs, ticketing, or one-off use cases.


# Pass types & templates

Understand pass templates and choose the right Apple Wallet and Google Wallet pass type for each use case.

A template defines the structure and design of a wallet pass. It controls the layout, labels, images, and which data points appear on the pass.

In The Wallet Crew, each template starts from a **pass type**. The pass type sets the base shape and constraints required by Apple Wallet and Google Wallet. The template then applies branding and mapping rules on top of it.

<details>

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

* Retail loyalty: a loyalty card pass shows member ID, tier, points, and a barcode.
* Gift cards: a stored-value pass shows current balance and updates after each redemption.
* Coupons: an offer pass shows an expiry date and a scannable code, then becomes redeemed.
* Events and visits: an event ticket pass shows venue and time, and supports fast scanning at entry.
* Membership and utilities: a generic pass supports staff badges, warranty cards, or pickup credentials.

</details>

## Template

A template is the configuration layer applied on top of an Apple Wallet / Google Wallet pass type. It is where branding and field mapping are defined once, then reused across all issued passes.

#### What a template controls

A template controls pass appearance and how data is presented:

* Visual design (colors, logos, images).
* Field layout (front fields, back fields, messages).
* Labels, ordering, and formatting (including translations).
* Barcode/QR configuration and its displayed value.
* Provider-specific constraints (Apple vs Google).

#### What a template does not control

A template is not the source of truth for business state. Validity, balances, entitlements, and redemption rules stay in upstream systems (CRM, loyalty engine, POS, ticketing, e-commerce, or a backend).

The Wallet Crew renders and updates the wallet pass from that source-of-truth data. This keeps the pass consistent with operations, while still benefiting from wallet UX (offline access, device-native presentation, and updates).

#### Why a template is required

Apple Wallet and Google Wallet don’t render arbitrary data. They render a pass that follows a predefined model. A template is the practical way to keep that model stable over time.

Templates make it possible to:

* Define a stable schema (which fields exist, and what they mean).
* Decide what appears on the front vs the back.
* Keep branding consistent across issued passes.
* Validate constraints early (required fields, supported formats, image sizes).

### Choose the right pass type

The Wallet Crew supports multiple pass types. The right choice depends on the operational workflow and which data must stay up to date.

#### Loyalty card

Use a loyalty card when the pass represents an ongoing customer relationship and must update over time.

Typical content includes a member identifier, tier/status, points or stamps, and support links. Redemption is commonly a barcode/QR scanned at POS, followed by a points or tier update.

More details: [Loyalty Card Template Configuration](/guides-design/design/loyalty-card-template-configuration).

#### Event ticket

Use an event ticket when the primary workflow is controlled access with fast entry scanning.

Typical content includes event name, venue, date/time, seat/section, gate, and a barcode/QR. Updates are useful for schedule changes, seat moves, or operational messages.

More details: [Event ticket](/guides-design/design/event-ticket).

#### Gift card

Use a gift card when the pass represents stored value that must decrease or increase over time.

Typical content includes a card identifier, balance and currency, expiry date when applicable, and a redemption barcode/QR (or NFC when supported). Balance updates after redemption are the core requirement.

More details: [Gift card](/guides-design/design/gift-card).

#### Offer

Use an offer for time-bound coupons or promotions, usually redeemed once.

Typical content includes an offer title, expiry date, conditions, and a redemption code (barcode/QR or promo code). The offer can be updated to reflect redemption state.

More details: [Offer](/guides-design/design/offer).

#### Generic

Use a generic pass when no dedicated pass type matches the use case, but a scannable or presentable credential is still needed.

Common patterns include membership cards that are not loyalty programs, staff badges, warranty cards, service bookings, or pickup credentials.

More details: [Generic](/guides-design/design/generic).

### When multiple templates make sense

Most projects start with one template per pass type. Multiple templates are useful when passes require different layouts, different constraints, or different content rules.

Common reasons include:

* Multiple brands, programs, or business units under one tenant.
* Different products with different information density (standard vs VIP, basic vs premium).
* Different legal text or customer support contacts per program.
* Different languages requiring different labels and content structure.
* Different barcode strategies or scanning contexts (POS vs access control).

### Next steps

Template creation and design are usually done once, then iterated with real operational feedback.

* Start with [How to Create a Template](/configure/advanced-configuration/wallet/template-configuration/how-to-create-a-template).
* For layout rules and asset requirements, use [Cards design (colors, images, and fields)](/configure/advanced-configuration/wallet/template-configuration/cards-design-colors-images-and-fields).
* For multi-language programs, use [How to Translate a template](/configure/advanced-configuration/wallet/template-configuration/how-to-translate-a-template).

## FAQ

<details>

<summary><strong>What is the difference between a pass type, a template, and a pass?</strong></summary>

Pass type is the base model required by Apple Wallet and Google Wallet (loyalty, offer, gift card, event ticket, generic).

A template is a configured instance of that pass type in The Wallet Crew. It defines branding, fields, and mapping rules.

A pass is the individual object installed by a customer. It uses one template at a time and can be updated over its lifecycle.

</details>

<details>

<summary><strong>Can a pass be updated after installation?</strong></summary>

Yes. Updates are a core wallet capability. The Wallet Crew updates the same installed pass, so customers don’t need to re-add it.

</details>

<details>

<summary><strong>Is one template enough for a whole program?</strong></summary>

Often yes. One template per pass type is a common baseline. Multiple templates are useful when different layouts or content rules are required.

</details>

<details>

<summary><strong>Does a template decide if a pass is valid?</strong></summary>

No. Validity and business state remain in source systems. The template controls how that state is displayed in Apple Wallet and Google Wallet.

</details>


# Loyalty Card Template Configuration

To enhance your customers experience, personalize your loyalty card with Apple and Google’s templates. Customize colors, images, and more with The Wallet Crew.

Whether you are a new client who needs to create the template for the passes that will be distributed to your customers, or a master of The Wallet Crew who needs to update an existing template, this article will help you navigate to our template designer. The goal is to configure a pass template that will reflect your brand identity, display the right information to your customers, and ensure a seamless experience across Apple Wallet and Google Wallet.

## Architecture

Apple and Google have their own loyalty pass templates as you can see below.

{% tabs %}
{% tab title="Apple" %}

<figure><img src="/files/4dPQom2opyhoyANqPjW7" alt="Architecture - Apple"><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Google" %}

<figure><img src="/files/PTGxezA9VPndQwvDR4Jz" alt="Architecture - Google"><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td align="center">Apple pass</td><td data-object-fit="contain" data-alt="Apple example loyalty card "><a href="/files/ip5cr5iIxgqGkViHLW7c">/files/ip5cr5iIxgqGkViHLW7c</a></td></tr><tr><td align="center">Apple pass</td><td data-object-fit="contain" data-alt="Apple example loyalty card "><a href="/files/bcqR0f3V8WDqkEXz4RBA">/files/bcqR0f3V8WDqkEXz4RBA</a></td></tr><tr><td align="center">Apple pass</td><td data-object-fit="contain" data-alt="Apple example loyalty card "><a href="/files/VSczKj1iFIYm7jyPKpZL">/files/VSczKj1iFIYm7jyPKpZL</a></td></tr></tbody></table>

<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td align="center">Google pass</td><td data-object-fit="contain"><a href="/files/GZeocG8KhVj8K7o0LjRG">/files/GZeocG8KhVj8K7o0LjRG</a></td></tr><tr><td align="center">Google pass</td><td data-object-fit="contain"><a href="/files/Hqy3rGeC4Gu1zF4uwCbQ">/files/Hqy3rGeC4Gu1zF4uwCbQ</a></td></tr><tr><td align="center">Google pass</td><td data-object-fit="contain"><a href="/files/HslbCb9L1nbs72hTz02a">/files/HslbCb9L1nbs72hTz02a</a></td></tr></tbody></table>

{% hint style="info" %}
**If you want to go further, find all the details of the two versions:**
{% endhint %}

**Apple:**

{% embed url="<https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html>" %}

**Android:**

{% embed url="<https://developers.google.com/wallet/retail/loyalty-cards/resources/template>" %}

### How to configure it on The Wallet Crew

With The Wallet Crew, you have access to a **template designer** that allows you to **personalize the loyalty cards** you will distribute to your clients. Let’s see in detail how to personalize each section!

## Apple

**Let’s take a look at the different sections of the Apple template designer.**

### General section

On the general section, you have two mandatory field that you must fill :

* **Description** : a brief description of the pass, that will appear on the back on the card
* **Organization name** : the name of your company or brand

You also have the possibility of putting a text next to your logo, **activate the sharing of the pass** if you want your customers to be able to share it or not with other people, the “void feature” for the coupons, a relevant and expiration date that are used for event tickets.

You can also **define the distance** from a relevant latitude and longitude that the pass is relevant, for **geofencing notifications.**

<figure><img src="/files/lepw353AKU2RBq2P9MFV" alt="Template designer general section"><figcaption><p>The section where you can personalize the general information</p></figcaption></figure>

### Barcode

Choose the **type of barcode** that is compatible with your point-of-sale software. The barcode value corresponds to the **identifiers** that will allow you to identify the card with your terminal in the store. Finally, the alternate text can be used to display the barcode data in case the barcode cannot be scanned.

<figure><img src="/files/T2VuvZHyPZDnC7q6XOtG" alt="Template designer barcode"><figcaption><p>The section where you can personalize your barcode preferences</p></figcaption></figure>

### Colors & Images

To change the background color of your card, simply **add the color code in the fields** provided for this purpose. To add an image, upload it from your device.

### Header Fields

This section is particularly important in the Apple version, as the cards are **stacked on top of each other**. Only the header of the card remains visible. Therefore, it is important that this section catches the eye and encourages clicking on the card, especially by displaying the most important information such as loyalty points, or other relevant information.

<figure><img src="/files/IrYhc7ncfLAIvexeFJlf" alt="Template designer header fields"><figcaption><p>The section where you can personalize the header fields</p></figcaption></figure>

### Front fields

The front fields are the fields that are used to **display information in the recto of the card**, under the strip image. The label you will choose is the same for every user (per language), but you can customize the value to display the name of the customer or the number of points.

<figure><img src="/files/qAcSA94etNUm2MzMcHBG" alt="Template designer front fields"><figcaption><p>The section where you can personalize the front fields</p></figcaption></figure>

{% hint style="warning" %}
**To personalize the front fields please refer to your tech team to find which dynamic value you have to write.**
{% endhint %}

### Backfields

This section, located on the back of the loyalty card, includes several useful pieces of information for the customer:

* How the loyalty program works
* Available rewards
* Receipts
* Personalized offers and messages
* The ability to add links, such as the location of their favorite store, a link to update their account and preferences, access to the terms and conditions, etc.

<figure><img src="/files/1vgBYMt2WWIaZgIYhwtf" alt="Template designer backfields"><figcaption><p>The section where you can personalize the backfields</p></figcaption></figure>

### Other sections

On Apple, you also have three other sections :

* **Locations** : Used for geofencing notifications.
* **Beacons** : Also used for geofencing notifications.
* **Associated store identifier** : You can link your application if it's located on Apple Store
* **NFC** : A feature that allows customers to exchange digital content, and connect electronic devices with a touch.

{% hint style="warning" %}
**Please contact your The Wallet Crew representative to activate these features**
{% endhint %}

{% hint style="danger" %}
**Once you’ve done some modifications, don’t forget to click on “save” on the top of your screen!**
{% endhint %}

***

## Google

**The Google template designer is a bit different than the Apple one.**

{% hint style="warning" %}
**Here are a few things you need to know before configuring your Google template:**
{% endhint %}

1. Some fields such as “issue” and “program name” are **mandatory**
2. Google preconfigures the fields based on their intended values, so it’s best not to enter the customer’s name in the loyalty points field, for example, even if that’s how you’d like it to appear on the pass
3. Dynamic values (e.g., {{firstName}}) should be **placed in dedicated dynamic fields**. ‘Label’ fields are intended for static text only.

**Let’s take a look at the different sections.**

### General section

On the general section, you have three **mandatory fields** that you must fill :

* **Issuer**: the name of the brand or company that issues the pass
* **Program name**: it appears on the front of the pass, it can be the name of your loyalty program for example
* **State**: the state of your pass (active, expired, completed, inactive)

<figure><img src="/files/SRUtflugbmpdz85yQGnq" alt="Google template designer general section"><figcaption><p>The section where you can personalize the general information</p></figcaption></figure>

### Barcode

Choose the **type of barcode** that is compatible with your point-of-sale software. The barcode value corresponds to the **identifiers** that will allow you to identify the card with your terminal in the store. Finally, the alternate text can be used to display the barcode data in case the barcode cannot be scanned.

<figure><img src="/files/NwGNkOqmJ8OTrvAZMvcE" alt="Google template designer Barcode"><figcaption><p>The section where you can personalize the barcode</p></figcaption></figure>

### Multiple devices and holders

When you configure a template, you need to decide **whether the customer can share their pass or not**. Regarding Google you have three option:

* **Multiple holders**: it means that the customer can share their pass with anyone
* **One user all device**: a customer but with several devices (a watch for example)
* **One user one device**

<figure><img src="/files/qDeMaxK5T4rmDUgUEZO7" alt="Google template designer multiple holders"><figcaption><p>The section where you can decide whether a customer can share his pass or not</p></figcaption></figure>

### Colors & Images

To change the background color of your card, simply **add the color code in the fields** provided for this purpose. To add an image, upload it from your device.

<figure><img src="/files/YBHmYVIUkUiUxzvoDshP" alt="Google template designer images and colors"><figcaption><p>The section where you can personalize the colors and images</p></figcaption></figure>

### Account

The account section is where you can put the **name of the customer** and his **identifier**.

<figure><img src="/files/gj9UNSNpS0yll9BZlrSo" alt="Google template designer account section"><figcaption><p>The section where you can configure the names and indentifers of your customers</p></figcaption></figure>

{% hint style="warning" %}
**Please note that it’s an optional field and that you can’t put a dynamic value on the label field.**
{% endhint %}

### Additional links

This appears on the back of the card, you can put the **link of a store or your website**!

<figure><img src="/files/AI2QBm5jSQRiCJwYH7C4" alt="Google template designer additional links"><figcaption><p>The section where you can add additional links</p></figcaption></figure>

### Loyalty Points, Rewards and Rewards Tiers

Those fields are used to set up the **loyalty points**, and the **rewards** or **rewards tiers** (status of the loyalty program for example).

<figure><img src="/files/3JlfjwQbjiJ3v7lScWnx" alt="Google template designer points" width="375"><figcaption><p>The section where you can configure the points and rewards of the pass</p></figcaption></figure>

### Messages

This section, located on the back of the loyalty card, includes several **useful pieces of information** for the customer:

* How the loyalty program works
* Available rewards
* The ability to add links, such as the location of their favorite store, a link to update their account and preferences, access to the terms and conditions, etc.

<figure><img src="/files/2rtQFCi2pTlswwsDTKvU" alt="Google template designer messages"><figcaption><p>The section where you can personalize the backfields of the pass</p></figcaption></figure>

### Value added opportunities

This section allows you to add a **small section at the bottom of the loyalty card**. This is used to display offers, or news.

<figure><img src="/files/GyppDAmbfikbGSELKQY5" alt="Google template designer added value opportunities"><figcaption><p>The section where you can personalize the section at the bottom of the pass</p></figcaption></figure>

{% hint style="danger" %}
**Once you’ve done some modifications, don’t forget to click on “save” on the top of your screen!**
{% endhint %}

## FAQ

<details>

<summary><strong>Do I need to save my configuration and update all the passes ?</strong></summary>

Once you've done editing your template, you have **two options:**

* Saving your configuration without pushing an update on all passes: this is the best option is you have a lot of passes. You can save your configuration and decide to schedule an update during the night to avoid the impact of mass updating.
* Saving your configuration and pushing an update: this is the best option if you are doing some tests or have a few passes in your environment.

</details>

<details>

<summary><strong>How to modify the configuration for another language?</strong></summary>

You have the ability to modify the design of the pass for each language. If you click on "general" in the menu, you can add a language. You'll then see it appear on the template designer and will be able to edit it.

</details>


# Event ticket

Deliver seamless event access with Apple and Google Wallet tickets. Personalize your passes with branding, visuals, and real-time event information using The Wallet Crew.

Whether you are a new client who needs to create the template for the tickets that will be distributed to your attendees, or a master of The Wallet Crew who needs to update an existing template, this article will help you navigate to our template designer. The goal is to configure a ticket template that will reflect your brand identity, clearly display essential event information, and ensure a smooth and secure experience across Apple Wallet and Google Wallet.

## Architecture

Apple and Google have their own ticket pass templates as you can see below.

{% tabs %}
{% tab title="Apple" %}

<figure><img src="/files/K0UJ6LArnEGrIBBdZRN7" alt="Architecture - Apple"><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Google" %}

<figure><img src="/files/I5FMwPKV5qyDpQqmv02F" alt="Architecture - Google"><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

<table data-view="cards"><thead><tr><th align="center"></th><th data-hidden data-card-cover data-type="image">Cover image</th></tr></thead><tbody><tr><td align="center">Apple ticket</td><td data-object-fit="contain"><a href="/files/zC8tblOJtTUUKrAWi2Fj">/files/zC8tblOJtTUUKrAWi2Fj</a></td></tr><tr><td align="center">Apple ticket</td><td data-object-fit="contain"><a href="/files/Uc3yt2PpLW7P9sumD1I6">/files/Uc3yt2PpLW7P9sumD1I6</a></td></tr><tr><td align="center">Apple ticket</td><td data-object-fit="contain"><a href="/files/hOPkp6qp3TCNCQdEUoxI">/files/hOPkp6qp3TCNCQdEUoxI</a></td></tr><tr><td align="center">Google ticket</td><td></td></tr><tr><td align="center">Google ticket</td><td></td></tr><tr><td align="center">Google ticket</td><td data-object-fit="contain"><a href="/files/uNGWuC08dclpPVnFJ1wn">/files/uNGWuC08dclpPVnFJ1wn</a></td></tr></tbody></table>

{% hint style="info" %}
**If you want to go further, find all the details of the two versions:**
{% endhint %}

**Apple:**

{% embed url="<https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html>" %}

**Google:**

{% embed url="<https://developers.google.com/wallet/tickets/events/resources/template?hl=fr>" %}

### How to configure it on The Wallet Crew

With The Wallet Crew, you have access to a **template designer** that allows you to **personalize the event tickets** you will distribute to your clients. Let’s see in detail how to personalize each section!

## Apple

**Let’s take a look at the different sections of the Apple template designer.**

### General section

On the general section, you have two mandatory field that you must fill :

* **Description** : a brief description of the pass, that will appear on the back on the card
* **Organization name** : the name of your company or brand

You also have the possibility of putting a text next to your logo, **activate the sharing of the ticket** if you want your customers to be able to share it or not with other people, the “void feature” for the coupons, a relevant and expiration date that are used for event tickets.

You can also **define the distance** from a relevant latitude and longitude that the pass is relevant, for **geofencing notifications.**

<figure><img src="/files/7OTXGLysIvLlhrPpOpQ0" alt="Event ticket - General section Apple"><figcaption></figcaption></figure>

### Barcode

Choose the **type of barcode** that is compatible with your control hardware. The barcode value corresponds to the **identifiers** that will allow you to identify the event ticket with your control terminal at the entrance. Finally, the alternate text can be used to display the barcode data in case the barcode cannot be scanned.

<figure><img src="/files/1pbyx9lJerR58qNvjWZ6" alt="Event ticket - Barcode Apple"><figcaption></figcaption></figure>

### Colors & Images

To change the background color of your ticket, simply **add the color code in the fields** provided for this purpose. To add an image, upload it from your device.

### Header Fields <a href="#header-fields" id="header-fields"></a>

This section is particularly important in the Apple version, as the tickets are **stacked on top of each other**. Only the header of the ticket remains visible. Therefore, it is important that this section catches the eye and encourages clicking on the card, especially by displaying the most important information such as the date, or other relevant information.

<figure><img src="/files/QpGj75bTghMSgQ82je6y" alt="Event ticket - Header fields Apple"><figcaption></figcaption></figure>

### Front fields

The front fields are the fields that are used to **display information in the recto of the ticket**, under the strip image. The label you will choose is the same for every user (per language), but you can customize the value to display the name of the event or the customer's seat.

<figure><img src="/files/v24wD1ZL8YKJJztvhUdL" alt="Event ticket - Front field Apple"><figcaption></figcaption></figure>

{% hint style="warning" %}
**To personalize the front fields please refer to your tech team to find which dynamic value you have to write.**
{% endhint %}

### Backfields <a href="#backfields" id="backfields"></a>

This section, located on the back of the event ticket, includes several useful pieces of information for the customer:

* How to get to the event
* Information regarding entrance
* Receipts
* The ability to add links, such as a link to listen to the artists, access to the terms and conditions, etc.

<figure><img src="/files/fb9IXEfJ3MvDQzl04HW5" alt="Event ticket - Backfields Apple"><figcaption></figcaption></figure>

### Other sections

On Apple, you also have four other sections :

* **Locations** : Used for geofencing notifications.
* **Beacons** : Also used for geofencing notifications.
* **Associated store identifier** : You can link your application if it's located on Apple Store
* **NFC** : A feature that allows customers to exchange digital content, and connect electronic devices with a touch.

{% hint style="warning" %}
**Please contact your The Wallet Crew representative to activate these features**
{% endhint %}

{% hint style="danger" %}
**Once you’ve done some modifications, don’t forget to click on “save” on the top of your screen!/**
{% endhint %}

***

## Google

**The Google template designer is a bit different than the Apple one.**

{% hint style="warning" %}
**Here are a few things you need to know before configuring your Google template:**
{% endhint %}

1. Some fields such as “issue” and “program name” are **mandatory**
2. Google preconfigures the fields based on their intended values, so it’s best not to enter the customer’s name in the Event name for example, even if that’s how you’d like it to appear on the pass
3. Dynamic values (e.g., {{firstName}}) should be **placed in dedicated dynamic fields**. ‘Label’ fields are intended for static text only.

**Let’s take a look at the different sections.**

### General section

On the general section, you have three **mandatory fields** that you must fill :

* **Issuer**: the name of the brand or company that issues the ticket
* **Event name**: it appears on the front of the pass, it can be the name of your event
* **State**: the state of your ticket (active, expired, completed, inactive)

<figure><img src="/files/uAw9DaJEcNgjpM66oiyI" alt="Event ticket - Google general"><figcaption></figcaption></figure>

### Barcode

Choose the **type of barcode** that is compatible with your control hardware. The barcode value corresponds to the **identifiers** that will allow you to identify the event ticket with your control terminal at the entrance. Finally, the alternate text can be used to display the barcode data in case the barcode cannot be scanned.

<figure><img src="/files/C20N8yNwk0jxaUcFWSet" alt="Event ticket - Barcode Google"><figcaption></figcaption></figure>

### Security

When you configure a template, you need to decide **whether the customer can share their pass or not**. Regarding Google you have three option:

* **Multiple holders**: it means that the customer can share their pass with anyone
* **One user all device**: a customer but with several devices (a watch for example)
* **One user one device**

<figure><img src="/files/RTrIPoqztb6aTRgBGHeG" alt="One user one device"><figcaption></figcaption></figure>

### Colors & Images

To change the background color of your ticket, simply **add the color code in the fields** provided for this purpose. To add an image, upload it from your device.

<figure><img src="/files/g7pJJ8CwCCLJVv9alKNR" alt="Event ticket - Colors and Images Google"><figcaption></figcaption></figure>

### Venue

A section to enter the detail of where the event will take place!

<figure><img src="/files/xBkCuVmnTkhmqM8Bav1L" alt="Event ticket - venue Google"><figcaption></figcaption></figure>

### Placement

You can define the gate, row, seat and section of your customer's ticket. Each field is optional.

{% hint style="warning" %}
**To personalize the placement fields please refer to your tech team to find which dynamic value you have to write.**
{% endhint %}

<figure><img src="/files/3BBbyCC5Oz9JkMudGOhL" alt="Event ticket - Placement Google"><figcaption></figcaption></figure>

### Confirmation

On the Google template, you can also define and display a confirmation code if it's required for your event. This is an optional field, if you don't have any confirmation code, you can select "Unspecified".

<figure><img src="/files/DCt4ORya31lcDJaLTK9V" alt="Event ticket - Confirmation Google"><figcaption></figcaption></figure>

### Additional links, Smart tap and Valid Time Interval

You can decide to add **additional links** to the customer's ticket, for exemple the event website link!

Furthermore, you can also configure the **Smart tap feature** that allows your customer to simply **validate their ticket** by taping their device on your compatible hardware terminal.

Finally, the Valid time interval section allows you to **define a start and an end date** to your event!

<figure><img src="/files/L1lRFBqHi9fPMvkDhxul" alt="Event ticket - Smart tap Google"><figcaption></figcaption></figure>

### Messages

This section, located on the back of the event ticket, includes several useful pieces of information for the customer:

* How to get to the event
* Information regarding entrance
* Receipts
* The ability to add links, such as a link to listen to the artists, access to the terms and conditions, etc.

<figure><img src="/files/e3yqPIJADdR0XzxCBjHp" alt="Event ticket - Backfields Google"><figcaption></figcaption></figure>

### Value added opportunities

This section allows you to add a **small section at the bottom of the ticket**. This is used to display offers, or news.

<figure><img src="/files/SbE66ZWAmsHwgbYpE4Kv" alt="Event ticket - Value Added Opportunity Google"><figcaption></figcaption></figure>

### Other sections

On Google, you also have four other sections :

* **Face Value** : The price of the ticket
* **App links** : Used to add a link for an application
* **Homepage** : Used to add the link of the event website
* **Locations** : Used for geofencing notifications

{% hint style="danger" %}
**Once you’ve done some modifications, don’t forget to click on “save” on the top of your screen!**
{% endhint %}

## FAQ

<details>

<summary><strong>Do I need to save my configuration and update all the passes at the same time?</strong></summary>

Once you've done editing your template, you have **two options:**

* Saving your configuration without pushing an update on all passes: this is the best option is you have a lot of passes. You can save your configuration and decide to schedule an update during the night to avoid the impact of mass updating.
* Saving your configuration and pushing an update: this is the best option if you are doing some tests or have a few passes in your environment.

</details>

<details>

<summary><strong>How to modify the configuration for another language?</strong></summary>

You have the ability to modify the design of the pass for each language. If you click on "general" in the menu, you can add a language. You'll then see it appear on the template designer and will be able to edit it.

</details>


# Gift card

Configure a Gift card pass template for Apple Wallet and Google Wallet. Show stored value, support barcode/NFC redemption, and keep balance up to date.

Whether you’re a new client looking to create the template for the gift cards you’ll distribute to your customers, or a Wallet Crew expert looking to update an existing template, this article will guide you through our template designer. The goal is to configure a gift card template that reflects your brand identity, displays the right information to your customers, and ensures a seamless experience across Apple Wallet and Google Wallet.

Use a **Gift card** pass when the pass represents **stored value**. This template is designed for balance display and balance updates.

Typical patterns:

* Initial balance at issuance
* Partial redemptions that decrease the balance
* Top-ups and refunds that update the same pass

If your pass is a discount coupon (not stored value), use [Offer](/guides-design/design/offer) instead.

### Architecture

Apple and Google have their own gift card pass templates as you can see below.

{% tabs %}
{% tab title="Apple" %}

<figure><img src="/files/O9qRQOP50QIqEAC76Uiz" alt="Apple gift card template"><figcaption></figcaption></figure>
{% endtab %}

{% tab title="Google" %}

<figure><img src="/files/QlhzzA59gWI4xxGtyJpI" alt="Google gift card template"><figcaption></figcaption></figure>
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**If you want to go further, find all the details of the two versions:**
{% endhint %}

**Apple:**

{% embed url="<https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html>" %}

**Google:**

{% embed url="<https://developers.google.com/wallet/retail/gift-cards/resources/template?hl=fr>" %}

### How to configure it on The Wallet Crew

With The Wallet Crew, you have access to a **template designer** that allows you to **personalize the gift cards** you will distribute to your clients. Let’s see in detail how to personalize each section.

## Apple

**Let’s take a look at the different sections of the Apple template designer.**

### General section

On the general section, you have two mandatory field that you must fill :

* **Description** : a brief description of the gift card, that will appear on the back on the card
* **Organization name** : the name of your company or brand

You also have the possibility of putting a text next to your logo, **activate the sharing of the gift card** if you want your customers to be able to share it or not with other people, the “void feature” for the coupons, a relevant and expiration date that are used for event tickets.

You can also **define the distance** from a relevant latitude and longitude that the pass is relevant, for **geofencing notifications.**

<figure><img src="/files/wwgawww5D1nO9ir7abwx" alt="Gift card - general section Apple"><figcaption></figcaption></figure>

### Barcode

Choose the **type of barcode** that is compatible with your point-of-sale software. The barcode value corresponds to the **identifiers** that will allow you to identify the card with your terminal in the store. Finally, the alternate text can be used to display the barcode data in case the barcode cannot be scanned.

<figure><img src="/files/DIr2SrsjP5bOGTFB7OI2" alt="Gift card - barcode Apple"><figcaption></figcaption></figure>

### Colors & Images

To change the background color of your card, simply **add the color code in the fields** provided for this purpose. To add an image, upload it from your device.

<figure><img src="/files/KYRJo2SiqVJy2CVqHSsY" alt="gift card - colors and images Apple"><figcaption></figcaption></figure>

### Header Fields

This section is particularly important in the Apple version, as the cards are **stacked on top of each other**. Only the header of the card remains visible. Therefore, it is important that this section catches the eye and encourages clicking on the card, especially by displaying the most important information such as the amount available.

<figure><img src="/files/SZfDASOs6YTshDvj5BoC" alt="gift card - header fields Apple"><figcaption></figcaption></figure>

### Front fields

The front fields are the fields that are used to **display information in the recto of the card**, under the strip image. The label you will choose is the same for every user (per language), but you can customize the value to display for example the expiry date of the card.

<figure><img src="/files/Bh5Nx8OA6yEmigwIJG0d" alt="display information in the recto of the card"><figcaption></figcaption></figure>

{% hint style="warning" %}
**To personalize the front fields please refer to your tech team to find which dynamic value you have to write.**
{% endhint %}

#### Backfields <a href="#backfields" id="backfields"></a>

This section, located on the back of the loyalty card, includes several useful pieces of information for the customer:

* The expiry date of the gift card
* The amount
* Receipts
* Personalized messages
* Links, such as the terms and conditions, etc.

<figure><img src="/files/V8pZ3UG9p6Rcp5TvnmyL" alt="gift card - backfields Apple"><figcaption></figcaption></figure>

### Other sections

On Apple, you also have three other sections :

* **Locations** : Used for geofencing notifications.
* **Beacons** : Also used for geofencing notifications.
* **Associated store identifier** : You can link your application if it's located on Apple Store
* **NFC** : A feature that allows customers to exchange digital content, and connect electronic devices with a touch.

{% hint style="warning" %}
**Please contact your The Wallet Crew representative to activate these features**
{% endhint %}

{% hint style="danger" %}
**Once you’ve done some modifications, don’t forget to click on “save” on the top of your screen!**
{% endhint %}

***

## Google

**The Google template designer is a bit different than the Apple one.**

{% hint style="warning" %}
**Here are a few things you need to know before configuring your Google template:**
{% endhint %}

1. Some fields such as issuer and program name are **mandatory**
2. Google preconfigures fields based on their intended values, so keep the balance in the dedicated balance/value fields
3. Dynamic values (e.g., {{balance}}) should be **placed in dedicated dynamic fields**. ‘Label’ fields are intended for static text only.

**Let’s take a look at the different sections.**

### General section

On the general section, you have three **mandatory fields** that you must fill :

* **Issuer**: the name of the brand or company that issues the pass
* **Program name**: it appears on the front of the pass, it can be the name of your loyalty program for example
* **Card number**: the number of the gift card

<figure><img src="/files/IKYpWol2HksHwUXegceC" alt="gift card - general section Google"><figcaption></figcaption></figure>

### Barcode

Choose the **type of barcode** that is compatible with your point-of-sale software. The barcode value corresponds to the **identifiers** that will allow you to identify the card with your terminal in the store. Finally, the alternate text can be used to display the barcode data in case the barcode cannot be scanned.

<figure><img src="/files/wYaThToM5AHANSvYrlkm" alt="gift card - barcode Google"><figcaption></figcaption></figure>

### Security

When you configure a template, you need to decide **whether the customer can share their pass or not**. Regarding Google you have three option:

* **Multiple holders**: it means that the customer can share their pass with anyone
* **One user all device**: a customer but with several devices (a watch for example)
* **One user one device**

<figure><img src="/files/gV3jAqgYvjP2iq56iGAO" alt="gift card - security Google"><figcaption></figcaption></figure>

### Colors & Images

To change the background color of your card, simply **add the color code in the fields** provided for this purpose. To add an image, upload it from your device.

<figure><img src="/files/6qUBnx4CiwMzXSypqQKs" alt="gift card - colors and images Google"><figcaption></figcaption></figure>

### Balance and Pin

In this section, you have to enter the dynamic value for the amount of the gift card and the currency as they are mandatory fields. You can also configure a Pin label and Pin if needed.

<figure><img src="/files/TtQJVM1wTTqQzJSmPkny" alt="gift card - balance and pin Google"><figcaption></figcaption></figure>

### Additional links, Smart tap and Valid Time Interval

You can decide to add **additional links** to the customer's gift card, for exemple your website link!

Furthermore, you can also configure the **Smart tap feature** that allows your customer to simply **validate their gift card** by taping their device on your compatible terminal.

Finally, the Valid time interval section allows you to **define when a gift card can be used!**

<figure><img src="/files/23FzL4KRTJYWzdHiofvL" alt="gift card - smart tap Google" width="375"><figcaption></figcaption></figure>

### Messages

This section, located on the back of the gift card, includes several useful pieces of information for the customer:

* The expiry date of the gift card
* The amount
* Receipts
* Personalized messages
* Links, such as the terms and conditions, etc.

<figure><img src="/files/JxCQfQRVufZlRPbNlljb" alt="gift card - messages Google"><figcaption></figcaption></figure>

### Value added opportunities

This section allows you to add a **small section at the bottom of the gift card**. This is used to display offers, or news.

### Other sections

On Google, you also have four other sections :

* **App links** : Used to add a link for an application
* **Homepage** : Used to add the link of the event website
* **Locations** : Used for geofencing notifications

{% hint style="danger" %}
**Once you’ve done some modifications, don’t forget to click on “save” on the top of your screen!**
{% endhint %}

### Next steps

* For design guidelines, start with [Card design](/configure/advanced-configuration/wallet/template-configuration/cards-design-colors-images-and-fields).
* To distribute the pass, use [Add to Wallet on a website](/guides-enrolment/enrolment/on-your-website).


# Offer

Configure an Offer pass template for Apple Wallet and Google Wallet. Use it for time-bound coupons and discounts.

## What are offers for?

Offers are designed to distribute promotional incentives to your customers in a simple, digital format. They help you drive traffic, boost conversions, and run time-limited campaigns directly within mobile wallets. An offer can be used to promote a discount, highlight a special event, reward specific customer segments, or support seasonal campaigns.

Whether you’re a new client looking to create a template for the offer you’ll distribute to your customers, or a Wallet Crew expert wanting to update an existing template, this article will guide you step by step through our Template Designer. The goal is to configure an offer template that reflects your brand identity, displays the right information to your customers, and ensures a seamless experience across Apple Wallet and Google Wallet.

Use an **Offer** pass when the pass is a **coupon**. It is the best fit for one-time or time-bound discounts.

Common patterns:

* A barcode or code redeemed at POS or in checkout
* An expiration date and usage constraints
* Campaign messaging pushed during the offer lifetime

If the pass represents stored value, use [Gift card](/guides-design/design/gift-card) instead.

### Architecture

Apple and Google have their own offer templates.

{% tabs %}
{% tab title="Apple" %}

<figure><img src="/files/3dU9ZGm6x4I1OH74OAyX" alt="The Wallet Crew offer - Apple architecture"><figcaption><p>Offer template designer (Apple)</p></figcaption></figure>
{% endtab %}

{% tab title="Google" %}

<figure><img src="/files/N525flGLiovMlFU4063A" alt="The Wallet Crew Offers - Google architecture"><figcaption><p>Offer template designer (Google)</p></figcaption></figure>
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**If you want to go further, find all the details of the two versions:**
{% endhint %}

**Apple**

{% embed url="<https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html>" %}

**Google**

{% embed url="<https://developers.google.com/wallet/retail/offers/resources/template>" %}

### How to configure it on The Wallet Crew

With The Wallet Crew, you have access to a template designer that allows you to personalize the offer passes you will distribute to your clients. Let’s see in detail how to personalize each section!

## Apple

**Let’s take a look at the different sections of the Apple template designer.**

### General section

On the general section, you have two mandatory field that you must fill :

* **Description** : a brief description of the pass, that will appear on the back on the card
* **Organization name** : the name of your company or brand

You also have the possibility of putting a text next to your logo, **activate the sharing of the ticket** if you want your customers to be able to share it or not with other people, and the **“void feature” for the coupons**.

You can also **define the distance** from a relevant latitude and longitude that the offer pass is relevant, for **geofencing notifications.**

<figure><img src="/files/6z8EPbECw4tLq8UbJHHz" alt="The Wallet Crew Offers - General Apple"><figcaption></figcaption></figure>

### Barcode

Choose the **type of barcode** that is compatible with your control hardware. The barcode value corresponds to the **identifiers** that will allow you to identify the offer in store. Finally, the alternate text can be used to display the barcode data in case the barcode cannot be scanned.

<figure><img src="/files/1V6uaiOraWI5z7262LyY" alt="The Wallet Crew Offers - Barcode Apple"><figcaption></figcaption></figure>

### Colors & Images

To change the background color of your offer pass, simply **add the color code in the fields** provided for this purpose. To add an image, upload it from your device.

### Header Fields <a href="#header-fields" id="header-fields"></a>

This section is particularly important in the Apple version, as the offers are **stacked on top of each other**. Only the header of the offer pass remains visible. Therefore, it is important that this section catches the eye and encourages clicking on the card, especially by displaying the most important information such as the amount left.

<figure><img src="/files/LlHkc0atyyQZZIIgFjc8" alt="The Wallet Crew Offers - Header field Apple"><figcaption></figcaption></figure>

### Front fields

The front fields are the fields that are used to **display information in the recto of the offer**, under the strip image. The label you will choose is the same for every user (per language), but you can customize the value to display the expiry date for example.

<figure><img src="/files/q6ncoyHkHnpvP16dB8ho" alt="The Wallet Crew Offers - Front fields Apple"><figcaption></figcaption></figure>

{% hint style="warning" icon="wand-magic-sparkles" %}
**To personalize the front fields please refer to your tech team to find which dynamic value you have to write.**
{% endhint %}

#### Backfields <a href="#backfields" id="backfields"></a>

This section, located on the back of the offer pass, includes several useful pieces of information for the customer:

* Expiry date
* Information regarding the brand
* Receipts
* The ability to add links, such as a website link

<figure><img src="/files/tJpzB8fs4eM96XMG0uby" alt="The Wallet Crew Offers - Backfields Apple"><figcaption></figcaption></figure>

### Other sections

On Apple, you also have four other sections :

* **Locations** : Used for geofencing notifications.
* **Beacons** : Also used for geofencing notifications.
* **Associated store identifier** : You can link your application if it's located on Apple Store
* **NFC** : A feature that allows customers to exchange digital content, and connect electronic devices with a touch.

{% hint style="warning" %}
**Please contact your The Wallet Crew representative to activate these features**
{% endhint %}

{% hint style="danger" %}
**Once you’ve done some modifications, don’t forget to click on “save” on the top of your screen!**
{% endhint %}

## Google

**The Google template designer is a bit different than the Apple one.**

{% hint style="warning" %}
**Here are a few things you need to know before configuring your Google template:**
{% endhint %}

1. Some fields such as “Redemption Channel ” and “Provider” are **mandatory**
2. Google preconfigures the fields based on their intended values
3. Dynamic values (e.g., {{firstName}}) should be **placed in dedicated dynamic fields**. ‘Label’ fields are intended for static text only.

**Let’s take a look at the different sections.**

### General section

On the general section, you have three **mandatory fields** that you must fill :

* **Issuer**: the name of the brand or company that issues the offer
* **General**: the title of the offer, such as "20% off any t-shirt."
* **State:** the state of your ticket (active, expired, completed, inactive)
* **Provider:** the offer provider (either the aggregator name or merchant name).
* **Redemption channel:** in store, online, both or unspecified

<figure><img src="/files/jtNaSPvQ5bBGSQsgKlxs" alt="The Wallet Crew offers - General Google"><figcaption></figcaption></figure>

### Barcode

Choose the **type of barcode** that is compatible with your control hardware. The barcode value corresponds to the **identifiers** that will allow you to identify the offer in store. Finally, the alternate text can be used to display the barcode data in case the barcode cannot be scanned.

<figure><img src="/files/lKAIsj5JNngjn8ejxP1G" alt="The Wallet Crew Offers - Barcode Google"><figcaption></figcaption></figure>

### Security

When you configure a template, you need to decide **whether the customer can share their pass or not**. Regarding Google you have three option:

* **Multiple holders**: it means that the customer can share their pass with anyone
* **One user all device**: a customer but with several devices (a watch for example)
* **One user one device**

<figure><img src="/files/6uP9xV3LWeMXwq4XLEyL" alt="The Wallet Crew Offers - Security Google"><figcaption></figcaption></figure>

### Colors & Images

To change the background color of your offer, simply **add the color code in the fields** provided for this purpose. To add an image, upload it from your device.

<figure><img src="/files/E9aX8joe4HdXzrk7JmQK" alt="The Wallet Crew Offers - Colors and images Google"><figcaption></figcaption></figure>

#### Additional links, Smart tap and Valid Time Interval <a href="#additional-links-smart-tap-and-valid-time-interval" id="additional-links-smart-tap-and-valid-time-interval"></a>

You can decide to add **additional links** to the customer's offer, for exemple the event website link!

Furthermore, you can also configure the **Smart tap feature** that allows your customer to simply **validate their offer** by taping their device on your compatible hardware terminal.

Finally, the Valid time interval section allows you to **define a start and an end date** to your offer!

<figure><img src="/files/1jrdEWcvwmpkcVovcetb" alt="The Wallet Crew Offers - Smart tap Google"><figcaption></figcaption></figure>

### Messages

This section, located on the back of the offer pass, can include several useful pieces of information for the customer:

* Expiry date
* Information regarding the brand
* Receipts
* The ability to add links, such as a website link

<figure><img src="/files/nm9HQD7Go06SI3FCg0bh" alt="The Wallet Crew Offers - Messages Google"><figcaption></figcaption></figure>

### Value added opportunities

This section allows you to add a **small section at the bottom of the offer**. This is used to display offers, or news.

<figure><img src="/files/1Kwda3oDy4V9i7lTklwK" alt="The Wallet Crew offers - Value added opportunities"><figcaption></figcaption></figure>

### Other sections

On Google, you also have four other sections :

* **Face Value** : The price of the offer
* **App links** : Used to add a link for an application
* **Homepage** : Used to add the link of the event website
* **Locations** : Used for geofencing notifications

{% hint style="danger" %}
**Once you’ve done some modifications, don’t forget to click on “save” on the top of your screen!**
{% endhint %}

#### FAQ

<details>

<summary><strong>When should we use “Face Value” on an offer?</strong></summary>

Use it when you want Google Wallet to display a monetary amount as part of the offer.

Keep it consistent with what your customer will see at checkout (currency, decimals, and wording in the offer title).

</details>

<details>

<summary><strong>Do App links require a mobile app?</strong></summary>

Yes. App links are for taking customers into your Android app (or to a page you control, depending on your setup).

If you don’t have an app, keep this section empty and use standard links in the pass instead.

</details>

<details>

<summary><strong>What happens if we set Locations?</strong></summary>

Locations can help surface the pass when customers are near a specific place, and they can support location-based interactions.

Start with a small set of store locations first. Validate the experience on real devices before rolling out to all stores.

</details>

### Next steps

* For design guidelines, start with [Card design](/configure/advanced-configuration/wallet/template-configuration/cards-design-colors-images-and-fields).
* To distribute the pass, use [Add to Wallet on a website](/guides-enrolment/enrolment/on-your-website).


# Generic

Configure a Generic pass template for Apple Wallet and Google Wallet. Use it for flexible membership cards, utility passes, and custom layouts.

The Generic pass is the most flexible pass type available. It is designed for use cases that don’t naturally fit into one of the dedicated templates such as loyalty cards, gift cards, offers, or tickets. If your pass doesn’t match a predefined category but still needs to be distributed through Apple Wallet or Google Wallet, the Generic template is likely the right choice.

Use a Generic pass when you need a flexible layout that does not fit a dedicated template (loyalty, gift card, offer, ticket).

**Typical use cases:**

* Membership cards that are not loyalty programs
* Partner or staff badges
* Utility passes (warranty card, pickup card, service card)
* Vouchers that are not discounts (free item, perk, entitlement)

If you’re unsure, start from [Pass types & templates](/guides-design/design/readme-1) and pick **Generic** only as a fallback.

### Architecture (Apple vs Google)

Apple and Google each provide their own Generic template structure.

{% tabs %}
{% tab title="Apple" %}

<figure><img src="/files/VajVaY51Fprxe0x7m4KI" alt="The Wallet Crew generic - Architecture Apple"><figcaption><p>Apple generic pass template</p></figcaption></figure>
{% endtab %}

{% tab title="Google" %}

<figure><img src="/files/Rpl47JqpdCKwxIRbYBSn" alt="The Wallet Crew generic - Architecture Google"><figcaption><p>Google generic pass template</p></figcaption></figure>
{% endtab %}
{% endtabs %}

{% hint style="info" %}
**If you want to go further, find all the details of the two versions:**
{% endhint %}

**Apple**

{% embed url="<https://developer.apple.com/library/archive/documentation/UserExperience/Conceptual/PassKit_PG/Creating.html>" %}

**Google**

{% embed url="<https://developers.google.com/wallet/reference/rest/v1/genericclass>" %}

### How to configure it on The Wallet Crew

With The Wallet Crew, you have access to a template designer that allows you to personalize the generic passes you will distribute to your clients. Let’s see in detail how to personalize each section!

## Apple

**Let’s take a look at the different sections of the Apple template designer.**

### General section

On the general section, you have two mandatory field that you must fill :

* **Description** : a brief description of the pass, that will appear on the back on the card
* **Organization name** : the name of your company or brand

You also have the possibility of putting a text next to your logo, **activate the sharing of the ticket** if you want your customers to be able to share it or not with other people, and the **“void feature” for the pass**.

You can also **define the distance** from a relevant latitude and longitude that the pass is relevant, for **geofencing notifications.**

<figure><img src="/files/MaDFBVHncpPJ4KiaYdwZ" alt="The Wallet Crew Generic - Apple general"><figcaption></figcaption></figure>

### Barcode

Choose the **type of barcode** that is compatible with your control hardware. The barcode value corresponds to the **identifiers** that will allow you to identify the pass in store. Finally, the alternate text can be used to display the barcode data in case the barcode cannot be scanned.

<figure><img src="/files/L5Kiy61k1Dk4YRJrPHbs" alt="The Wallet Crew generic - Barcode Apple"><figcaption></figcaption></figure>

### Colors & Images

To change the background color of your pass, simply **add the color code in the fields** provided for this purpose. To add an image, upload it from your device.

### Header Fields <a href="#header-fields" id="header-fields"></a>

This section is particularly important in the Apple version, as the offers are **stacked on top of each other**. Only the header of the offer pass remains visible. Therefore, it is important that this section catches the eye and encourages clicking on the card, especially by displaying the most important information such as the name of the customer.

<figure><img src="/files/MHG4emhjsL3vTfuVXDCp" alt="The Wallet Crew Generic - Header fields Apple"><figcaption></figcaption></figure>

### Front fields

The front fields are the fields that are used to **display information in the recto of the pass**, under the strip image. The label you will choose is the same for every user (per language), but you can customize the value to display the expiry date for example.

<figure><img src="/files/u94eMtb8GrOQsgnA8GWx" alt="The Wallet Crew generic - Front fields Apple"><figcaption></figcaption></figure>

{% hint style="warning" %}
**To personalize the front fields please refer to your tech team to find which dynamic value you have to write.**
{% endhint %}

### **Backfields**

This section, located on the back of the pass, includes several useful pieces of information for the customer:

* Expiry date
* Information regarding the brand
* Receipts
* The ability to add links, such as a website link

<figure><img src="/files/lfwMUrGLjBTxMmftFjT4" alt="The Wallet Crew generic - Backfields Apple"><figcaption></figcaption></figure>

### Other sections

On Apple, you also have four other sections :

* **Locations** : Used for geofencing notifications.
* **Beacons** : Also used for geofencing notifications.
* **Associated store identifier** : You can link your application if it's located on Apple Store
* **NFC** : A feature that allows customers to exchange digital content, and connect electronic devices with a touch.

{% hint style="warning" %}
**Please contact your The Wallet Crew representative to activate these features**
{% endhint %}

{% hint style="danger" %}
**Once you’ve done some modifications, don’t forget to click on “save” on the top of your screen!**
{% endhint %}

## Google

**The Google template designer is a bit different than the Apple one.**

{% hint style="warning" %}
**Here are a few things you need to know before configuring your Google template:**
{% endhint %}

1. Some fields such as “General ” and “Header” are **mandatory**
2. Google preconfigures the fields based on their intended values
3. Dynamic values (e.g., {{firstName}}) should be **placed in dedicated dynamic fields**. ‘Label’ fields are intended for static text only.

**Let’s take a look at the different sections.**

### General section

On the general section, you have three **mandatory fields** that you must fill :

* **General**: the title of the pass.
* **Header:** the header of the pass
* **Sub Header :** the subheader of the pass, such as location where this pass can be used
* **State:** the state of the object.

<figure><img src="/files/7NQP0Tgsae7CJsSUstCv" alt="The Wallet Crew generic - General Google"><figcaption></figcaption></figure>

### Security

When you configure a template, you need to decide **whether the customer can share their pass or not**. Regarding Google you have three option:

* **Multiple holders**: it means that the customer can share their pass with anyone
* **One user all device**: a customer but with several devices (a watch for example)
* **One user one device**

<figure><img src="/files/W8p9WVyL51PtOnr6GPOM" alt="The Wallet Crew generic - Security Google"><figcaption></figcaption></figure>

### Colors & Images

To change the background color of your pass, simply **add the color code in the fields** provided for this purpose. To add an image, upload it from your device.

<figure><img src="/files/0Ef0wJCCapJ8haZelTqk" alt="The Wallet Crew Generic - Colors and images Google"><figcaption></figcaption></figure>

#### Additional links, Smart tap and Valid Time Interval <a href="#additional-links-smart-tap-and-valid-time-interval" id="additional-links-smart-tap-and-valid-time-interval"></a>

You can decide to add **additional links** to the customer's pass, for exemple the event website link!

Furthermore, you need to configure the **Smart tap feature** that allows your customer to simply **validate their pass** by taping their device on your compatible hardware terminal.

Finally, the Valid time interval section allows you to **define a start and an end date** to your pass!

### Value added opportunities

This section allows you to add a **small section at the bottom of the pass**. This is used to display offers, or news.

<figure><img src="/files/fheIDEqgJ7xJeOjAHpyG" alt="The Wallet Crew Generic - Value added opportunities Google"><figcaption></figcaption></figure>

### Other sections

On Google, you also have four other sections :

* **App links** : Used to add a link for an application
* **Homepage** : Used to add the link of the event website
* **Locations** : Used for geofencing notifications

{% hint style="danger" %}
**Once you’ve done some modifications, don’t forget to click on “save” on the top of your screen!**
{% endhint %}

### Next steps

* For design guidelines, start with [Card design](/configure/advanced-configuration/wallet/template-configuration/cards-design-colors-images-and-fields).
* To distribute the pass, use [Add to Wallet on a website](/guides-enrolment/enrolment/on-your-website).


# Enrolment Guides

Choose and design the right pass enrolment and delivery channel.

Enrolment defines how a customer gets an Apple Wallet pass or a Google Wallet pass installed. For most projects, enrolment is a key topic. It requires analysis and design.

Enrolment is not just a delivery mechanism. It is the system that connects acquisition, identity resolution, data collection, and pass installation.

Every design choice made in enrolment has downstream effects. It can improve conversion, strengthen data quality, reduce duplicates, and make re-installation reliable after a device change. Over time, these details decide whether a Wallet program becomes a habit or stays a one-off install.

<details>

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

* **Loyalty acquisition in-store:** a QR code opens an enrolment form and issues a loyalty card.
* **Gift card access after purchase:** an account page exposes “Add to Wallet” to install the gift card.
* **Membership program:** an email link lets customers re-install a member card after device change.
* **Event ticketing:** a post-purchase page or in-app screen triggers ticket installation.

</details>

<table data-view="cards"><thead><tr><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h3>Enrolment form</h3></td><td><a href="/files/kAqdFSlDdLRywPQQGJqA">/files/kAqdFSlDdLRywPQQGJqA</a></td><td><a href="/pages/TGicq2u9Q05Orb6eoG4h">/pages/TGicq2u9Q05Orb6eoG4h</a></td></tr><tr><td><h3>Website embed</h3></td><td><a href="/files/tsfUngHdMvbS8qY4aXqo">/files/tsfUngHdMvbS8qY4aXqo</a></td><td><a href="/pages/Z5RlzwsQyC52tRTU3B5u">/pages/Z5RlzwsQyC52tRTU3B5u</a></td></tr><tr><td><h3>Email Delivery</h3></td><td><a href="/files/K0epD56Zjlu1kiTY4YKR">/files/K0epD56Zjlu1kiTY4YKR</a></td><td><a href="/pages/Jlu4GvVpp6ZKaEXtlTCa">/pages/Jlu4GvVpp6ZKaEXtlTCa</a></td></tr><tr><td><h3>Mobile App Integration</h3></td><td><a href="/files/Dx6KBrHSgJWC3ZchP8Mw">/files/Dx6KBrHSgJWC3ZchP8Mw</a></td><td><a href="/pages/Vd98rq4EVfeW8dW1TLFB">/pages/Vd98rq4EVfeW8dW1TLFB</a></td></tr><tr><td><h3>Download pages</h3></td><td></td><td><a href="/pages/8mhoewUTcBWgyos9k9ZB">/pages/8mhoewUTcBWgyos9k9ZB</a></td></tr></tbody></table>

## Enrolment channels

The Wallet Crew offers multiple ways to enrol at the best time in the customer journey.

In practice, enrolment is where “Add to Wallet” is exposed, for example through a QR code, a website button, an email link, or an in-app action.

In practice, “best time” usually means a moment where intent is high and identity is easy to resolve. For loyalty and membership, that moment is often the join action. For tickets and gift cards, that moment is often an authenticated surface or a post-purchase screen.

The pages above cover the main enrolment and delivery channels supported by The Wallet Crew.

Some projects require deeper integration to keep enrolment fully embedded in existing web or app flows. In those cases, The Wallet Crew SDK can be used on a website or in a native mobile app, depending on the chosen architecture.

Download pages support delivery after a pass already exists. They display wallet actions for one pass or a list of passes. They do not collect registration data or consent. See [Download pages](/guides-enrolment/enrolment/download-pages).

## Other supported patterns

Some projects require additional enrolment patterns. The most common one is **bulk enrolment**. This is used when a Brand already has a customer or member list and wants to issue passes at scale, for example during a migration, for season members, or for corporate programs.

Bulk enrolment can be triggered from the back-office (CSV or Excel import). It can also be automated via API or via file-based integration such as SFTP, depending on the project scope. For migration projects, see [Pass migration](https://docs.thewalletcrew.io/configuration/wallet/import-and-export/pass-migration).

The output of bulk enrolment is typically a **pass link** per customer. The Brand can distribute that link through its own channels. The end-to-end sending can also be delegated to The Wallet Crew, when required.

Bulk enrolment separates pass generation from pass distribution. This keeps rollouts flexible at scale. If passes must be handed over outside The Wallet Crew, see [Export passes from TWC to another provider](https://docs.thewalletcrew.io/configuration/wallet/import-and-export/pass-migration/export-passes-from-twc-to-another-provider).

## Why enrolment design matters

Enrolment is part of the product experience. It defines the “front door” to a wallet program. It also defines the rules to identify a customer and decide which pass should be installed.

#### Start from the value moment

The right design usually starts with the moment where the pass becomes valuable. The chosen channel should match that moment.

* In-store acquisition → QR + enrolment form
* Authenticated purchase or account access → website embed or native app integration
* Existing pass delivery → download page
* Migration or legacy program seeding → bulk enrolment
* Re-install or device change → email delivery as a resilient fallback

Renewal and re-install moments should be treated as first-class flows. They drive long-term adoption and reduce support load.

#### Choose an identity strategy early

Identity design is the next constraint. A matching key is needed to avoid duplicates and ensure the right pass is returned. Email is common, but it is not always stable. Phone number, membership number, ticket order ID, or a CRM identifier can be better keys depending on the program.

When enrolment relies on a form, identity resolution and eligibility checks are often implemented through [Social sign-in](/guides-enrolment/enrolment/enrolment-form/social-sign-in) and [Validation rules](/guides-enrolment/enrolment/enrolment-form/validation-rules).

#### Keep data collection minimal

Data collection should stay minimal at enrolment. Fields that are not required for issuance can be collected later. This typically improves completion rate while keeping data quality high.

When consent is captured during enrolment, align consent wording and storage with the Brand privacy policy, the [Privacy and security](https://docs.thewalletcrew.io/policies/privacy-and-security) policies, and the [Data Processing Agreement model](https://docs.thewalletcrew.io/policies/privacy-and-security/data-processing-agreement-model).

## Recommended approach

Most projects converge to a simple approach: one primary channel, plus one fallback channel.

The primary channel should match where the program “lives” for customers. Loyalty and membership often live in-store or in campaign acquisition, which makes QR → form a strong default. Tickets and gift cards often live in authenticated environments, which makes website or app distribution a strong default.

The fallback channel is usually email delivery, because it is resilient across devices and platforms. It is also a strong re-install path when a pass is deleted or when a customer changes phone.

## FAQ

<details>

<summary><strong>Is there a difference between enrolment and distribution?</strong></summary>

In this documentation, there is no difference.

Both terms refer to the same topic: choosing the entry point (QR, web, email, app), resolving identity when needed, and delivering the Apple Wallet / Google Wallet installation experience.

</details>

<details>

<summary><strong>Which channel works best for loyalty and member cards?</strong></summary>

An enrolment form is usually the best starting point.

It supports data capture, eligibility rules, and identity. It also supports in-store QR acquisition and staff-assisted flows.

</details>

<details>

<summary><strong>Which channel works best for tickets and gift cards?</strong></summary>

A logged-in website surface or an in-app surface is often the cleanest path.

It avoids re-collecting data and it uses the existing account context to resolve identity.

</details>

<details>

<summary><strong>Why keep email delivery if a website or app exists?</strong></summary>

Email is a strong fallback for desktop and for device changes.

It also reduces support load, because it creates a self-service re-install path.

</details>

<details>

<summary><strong>What does “bulk enrolment” mean in practice?</strong></summary>

Bulk enrolment means issuing passes for an existing list of customers or members.

It is typically used for migrations, seeding a loyalty base, corporate memberships, or season programs. It usually produces a pass link per customer, then distribution happens either through Brand channels or through a delegated send operated by The Wallet Crew.

</details>


# Enrolment form

Set up an enrolment form to collect customer data, apply rules, and issue Apple Wallet and Google Wallet passes.

An enrolment form is the web page customers use to join a program and save a pass. It is also the key conversion moment where a customer moves from interest to ownership, for example after scanning a QR code, clicking an email link, or tapping a CTA.

In The Wallet Crew, the enrolment form is the "front door" to the Brand's Apple Wallet and Google Wallet experience. It collects the required data, applies Brand rules, captures required consents, and then issues the pass with the correct "Add to Wallet" experience. When a customer submits the form, TWC creates a customer profile — equivalent to a loyalty account — and immediately issues the wallet pass.

<figure><img src="/files/kAqdFSlDdLRywPQQGJqA" alt="Example enrolment form used to collect customer data before pass issuance"><figcaption><p>Example enrolment form used to collect customer data before pass issuance.</p></figcaption></figure>

In The Wallet Crew, an enrolment form can work for new customers and returning customers. If a customer is already known, the form can identify them early and avoid asking the same questions again.

<details>

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

* A retail Brand places a QR code at checkout to enrol customers in loyalty.
* An event organizer uses a short form to issue a membership pass before presales.
* A luxury Brand sends an email link after an in-store visit to create a client profile.
* A ticketing solution embeds a form step to capture missing data before issuing a pass.

</details>

## From acquisition to Wallet

An enrolment form sits between the Brand acquisition channel and the pass template. Customers reach it from a QR code, a website CTA, an email, a mobile app, or a POS flow. The Wallet Crew then creates or updates the wallet pass information and generates the correct “Add to Wallet” experience.

Enrolment performance depends heavily on timing. The same form can be distributed at high-intent moments, such as in-store QR codes, post-purchase emails, mobile app deep links, POS integrations, or clienteling follow-ups.

To get more information about other distribution channels, see:

* [On your website](/guides-enrolment/enrolment/on-your-website)
* [Via Email](/guides-enrolment/enrolment/via-email)
* [On your mobile app](/guides-enrolment/enrolment/readme-1)

## What the experience looks like

Most enrolment forms are designed to complete in under a minute on mobile. This matters in real life. Many customers enrol while standing in a store, walking, or switching between apps.

### Typical flow

The exact screens depend on the configuration, but the logic stays the same.

1. The customer opens the form from a link or QR code.
2. The form optionally identifies the customer early (social sign-in or email check-in).
3. The customer fills the missing fields and accepts consents if needed.
4. The Wallet Crew creates or updates the customer profile.
5. The pass is issued and the customer saves it to Apple Wallet or Google Wallet.

{% hint style="info" %}
“Minimum viable enrolment” usually converts best. Collect only what is needed to issue the pass and comply. Profiles can be enriched later.
{% endhint %}

## Configure for performance

An enrolment form combines UX choices and data rules. The goal is to remove friction without lowering data quality.

### Fields, data, and validation

Each additional field increases drop-off risk. Fields should be added only when they drive a clear business outcome. Typical examples are an email address or a phone number.

Validation rules protect data quality. They also reduce support costs later. To get more information about supported rules like `required`, `minLength`, `maxLength`, `email`, and `phone`, see [Validation rules](/guides-enrolment/enrolment/enrolment-form/validation-rules).

### Branding and design

Customers need to trust the page instantly. The form should display the Brand logo and colors. Copy should match the Brand voice. The main CTA should be visible without scrolling.

To get more information about what can be customized (logo, colors, typography, header image, light/dark palette), see [Design](/guides-enrolment/enrolment/enrolment-form/design).

### Identify returning customers

If the customer already exists, the best form is the one that does not ask questions again. The Wallet Crew supports two common patterns.

Social sign-in gives a one-tap identification flow on mobile. It reduces typos. It typically reduces duplicates. To get more information, see [Social sign-in](/guides-enrolment/enrolment/enrolment-form/social-sign-in).

Email check-in adds an email-first step. It lets existing customers be detected early. It can also add a security step if email verification is required. For the setup flow, see [Enable email check-in on enrolment forms](https://docs.thewalletcrew.io/configuration/enrolment-form/enable-email-check-in-on-enrolment-forms).

{% hint style="warning" %}
Identification is not consent. Marketing consent should be collected explicitly and separately.
{% endhint %}

### In-store context with redirects and stores

Many Brands run the same enrolment form across all stores. They still want store-level tracking and personalization. This is where redirects help.

A redirect is a short, managed URL that can add parameters like `storeId`, language, or campaign source. The resulting QR code can be printed and deployed in-store. See [Redirects](/guides-enrolment/enrolment/enrolment-form/redirect).

Store data is the reference list behind `storeId`. It is useful when a store name or address should be displayed in the journey or on the pass. See [Stores](/guides-enrolment/enrolment/enrolment-form/stores).

## Data quality

Data quality is a primary outcome of enrolment design. It impacts identity resolution, segmentation, personalization, and reporting. It also reduces operational effort later, especially when customer data is synced to a CRM.

High-quality data usually comes from a combination of short forms, clear intent, and strict rules at capture time.

### Why enrolment is a data-quality moment

Enrolment happens when intent is high. This is when customers are most likely to provide accurate identifiers. Self-enrolment also helps because customers know how to write their own personal data. Mobile auto-complete reduces typing effort and common typos, especially on names, emails, and phone numbers.

The same moment can create low-quality data when the form is too long or unclear. Drop-off increases, and placeholder entries become more common.

### What improves data quality

The strongest lever is collecting less data, but validating it better. Required fields should be limited to true identifiers needed for profile creation and pass issuance. Optional fields should stay optional, with enrichment happening later through engagement.

Validation should be strict and consistent across channels. This is where most duplicates start. To get more information about supported rules like `required`, `minLength`, `maxLength`, `email`, and `phone`, see [Validation rules](/guides-enrolment/enrolment/enrolment-form/validation-rules).

Identification patterns also improve data quality. Social sign-in reduces typing and tends to reduce duplicates. Email check-in helps detect existing customers early and prevents re-creating profiles for known customers.

## Privacy, GDPR & CCPA compliance

Enrolment forms collect personal data. They must be treated as production-grade identity surfaces, with the same rigor as any other identity entry point.

The Wallet Crew is deployed worldwide. Regional requirements vary by market, industry, and use case. The platform supports structured consent capture designed to align with GDPR (European Union), CCPA (California), and similar regional privacy frameworks. The [Privacy and security](https://docs.thewalletcrew.io/policies/privacy-and-security) section groups the relevant policies. The [Data Processing Agreement model](https://docs.thewalletcrew.io/policies/privacy-and-security/data-processing-agreement-model) provides the formal privacy framework reference. For common operational questions, see the [Data protection FAQ](https://docs.thewalletcrew.io/policies/privacy-and-security/data-protection-faq). The Wallet Crew also offers a DPO service to help brands operationalize privacy requirements and keep consent practices consistent across regions.

### Self-enrolment strengthens compliance

Self-enrolment strengthens transparency because customers see exactly what data is collected and why. Consent language is read directly and in context. Information can be provided privately, which is especially important in-store where personal information would otherwise be shared out loud.

Self-enrolment also improves data quality. Mobile auto-complete reduces typing effort and typos. Customers typically enter personal data more accurately than staff-assisted capture, especially for names, emails, and phone numbers.

This reduces ambiguity, strengthens identity resolution, and improves defensibility during audits, while keeping the enrolment experience fast on mobile.

### Explicit and unambiguous consent

Marketing consent must remain separate from identification. Consent language should be clear, readable on mobile, and collected as an explicit opt-in. Pre-checked boxes should be avoided. A visible link to the Brand privacy policy should sit next to the consent field.

For wallet notifications and consent patterns, align the enrolment form with the Brand privacy policy and the regional consent requirements.

To update the consent wording yourself, see [Localize form text and consent wording](/configure/advanced-configuration/enrolment-form#localize-form-text-and-consent-wording) in the Enrolment Form configuration reference.

### Collect less, but collect better

Data minimization improves both compliance and performance. A small set of high-quality identifiers, validated strictly at capture time, is easier to justify legally and easier to use operationally. For practical guidance on improving capture quality, see [Data quality](#data-quality).

## Why enrolment matters

Enrolment is not only a step before pass issuance. It is where identity, consent, attribution, and store context can be captured while intent is high.

Optimizing this moment typically improves conversion to Wallet, reduces duplicates, and strengthens compliance posture.

## FAQ

<details>

<summary><strong>Is an enrolment form the same thing as a registration form?</strong></summary>

Yes, in practice.

In The Wallet Crew docs, both terms are used. “Enrolment form” is the broader term. It covers registration, identification, profile update, and pass issuance in one journey.

</details>

<details>

<summary><strong>Can one form work for both new and returning customers?</strong></summary>

Yes.

Social sign-in or email check-in can identify returning customers early. The form can then skip fields already known and focus on the pass installation step.

</details>

<details>

<summary><strong>What is the best channel for enrolment: QR code, email, website, or app?</strong></summary>

Pick based on where customers already are.

QR codes work best when the moment happens in store. Email works best when an address already exists. A website or mobile app works best when the customer is already logged in and identity can be resolved without extra steps.

</details>

<details>

<summary><strong>Should we make all fields mandatory to keep data clean?</strong></summary>

No.

Too many required fields increase abandonment and often produce fake data. Only true identifiers should be required. They should be validated strictly. The rest can be collected later.

</details>

<details>

<summary><strong>Do we need social sign-in if we already use email?</strong></summary>

Not always, but it often helps.

Social sign-in reduces typing and email typos on mobile. It can also improve matching when email is used as a primary key. An email fallback is typically kept for customers who do not want to use a provider.

</details>

<details>

<summary><strong>Does identification replace marketing consent?</strong></summary>

No.

Identification proves who the customer is. Marketing consent grants permission to send marketing messages. Keeping them separate improves compliance and avoids ambiguity during audits.

</details>


# Social sign-in

Let users authenticate on enrolment forms with Apple, Google, LINE, or Facebook. Use the provider-verified email to create or retrieve a customer profile.

Social sign-in (also called **social login**) lets users authenticate on enrolment forms. It supports **Sign in with Apple**, **Google Sign-In**, **LINE Login**, and **Facebook Login**.

It works well for mobile flows on **iOS and Android**. It identifies customers early in the journey. It avoids password creation. It reduces duplicates caused by mistyped emails.

<figure><img src="/files/MIkZk5esRY3eTwaUyGVD" alt="Enrolment form screen showing social sign-in buttons above the form fields"><figcaption><p>Place provider buttons above the form fields to encourage one-tap sign-in.</p></figcaption></figure>

{% hint style="info" %}
This page covers **how social sign-in behaves** in The Wallet Crew (UX, matching, data expectations).

It does **not** cover provider console setup. Use these setup guides:

* [Apple Sign-in configuration](/guides-enrolment/enrolment/enrolment-form/social-sign-in/apple-sign-in)
* [Google Sign-in configuration](/guides-enrolment/enrolment/enrolment-form/social-sign-in/google-sign-in)
* [LINE Sign-in configuration](/guides-enrolment/enrolment/enrolment-form/social-sign-in/line-sign-in)
* [Facebook Sign-in configuration](/guides-enrolment/enrolment/enrolment-form/social-sign-in/facebook-sign-in)
  {% endhint %}

<details>

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

* **In-store QR enrolment:** Customers scan a QR and enrol in one tap.
* **Returning member enrolment:** Match the profile and skip known fields.

</details>

### What it does

Social sign-in adds a **provider-backed identity step** to an enrolment form. The Wallet Crew uses it to **resolve a customer early**. That customer context changes how the form behaves.

The user taps a provider button. The provider authenticates the user. It returns an identity payload. The Wallet Crew extracts usable attributes from that payload. The Wallet Crew then applies your matching rules.

One form can support new and returning users. If a match is found, The Wallet Crew loads the profile. The user continues as a known customer. If no match is found, the user continues as new. A profile is created on submission.

One form can support multiple social sign-in at the same time (Apple, Google, Line, Facebook)

### What this page does not cover

Provider setup is intentionally kept out of this page.

This page does **not** include:

* Apple/Google/LINE/Facebook console screenshots and step-by-step setup
* Client IDs, service IDs, keys, secrets, redirect URLs, or domain allowlists
* Provider-specific error troubleshooting (`origin_mismatch`, Apple relay email config, etc.)

Use the provider setup guides linked above for that.

### Benefits

* Faster enrolment with fewer typed fields.
* More reliable matching with provider‑verified email.
* Fewer duplicates caused by email typos.
* Better completion rates on mobile and QR journeys (less friction).
* One enrolment flow for new and returning users.

#### UX patterns (fast enrolment, low friction)

Social sign-in works best when the form is built around it. Put provider buttons **above** the form fields. Make them the default entry path on mobile.

After sign-in, hide the email field. Or make it read-only. Keep a fallback like “Continue with email”. Skip fields you already have for matched users. Keep the new-user path short and focused.

{% hint style="warning" %}
Apple “Hide My Email” can return a relay email. Avoid copy like “we found your personal email”. Names can be missing. Do not block submission on first/last name.
{% endhint %}

#### Enrolment speed & efficiency (what to optimize)

Optimize for a flow that completes in seconds. Assume the user is in a queue. Ask only for what you truly need at enrolment.

Prefer progressive profiling after enrolment. Use social sign-in to capture the matching key. Keep consents explicit but short. Keep long legal text off the critical path. Make errors specific and actionable.

For in-store QR flows, assume bad connectivity. Avoid extra network round-trips. Only add checks that reduce real fraud.

#### Security considerations

Social sign-in is a strong **identity signal**. It is not full account security. Treat it as proof the user controls a provider account.

You benefit from provider controls like device trust and MFA. You typically get a verified email. You still need a rule for **account ownership** in your CRM. You also do not get automatic linking across providers.

### Activation

You enable social sign-in in two places:

1. Configure the provider (Apple / Google / LINE / Facebook).
2. Enable the provider button on the enrolment form.

Provider setup is a one-time configuration per provider. Use these guides:

<table data-card-size="large" data-view="cards"><thead><tr><th align="center"></th><th data-hidden data-card-target data-type="content-ref">Setup guide</th><th data-hidden data-card-cover data-type="image">Preview</th></tr></thead><tbody><tr><td align="center"><strong>Google</strong></td><td><a href="/spaces/lFokgwgJiwLXu7G8MVSJ/pages/YbiCpvSEuvpZOmdz0GCp">/spaces/lFokgwgJiwLXu7G8MVSJ/pages/YbiCpvSEuvpZOmdz0GCp</a></td><td><a href="/files/BUn9l4M9E7WjzL90YhPE">/files/BUn9l4M9E7WjzL90YhPE</a></td></tr><tr><td align="center"><strong>Apple</strong></td><td><a href="/spaces/lFokgwgJiwLXu7G8MVSJ/pages/a0zgBQTqJBPXJcoZKo9K">/spaces/lFokgwgJiwLXu7G8MVSJ/pages/a0zgBQTqJBPXJcoZKo9K</a></td><td><a href="/files/QNDF5EHPRT2gnicaQUyx">/files/QNDF5EHPRT2gnicaQUyx</a></td></tr><tr><td align="center"><strong>LINE</strong></td><td><a href="/spaces/lFokgwgJiwLXu7G8MVSJ/pages/GnyRAqyhF74SkeIqAO44">/spaces/lFokgwgJiwLXu7G8MVSJ/pages/GnyRAqyhF74SkeIqAO44</a></td><td><a href="/files/1K4g7puLRH6mNcTsy5vG">/files/1K4g7puLRH6mNcTsy5vG</a></td></tr><tr><td align="center"><strong>Facebook</strong></td><td><a href="/spaces/lFokgwgJiwLXu7G8MVSJ/pages/YzI8PWWyMC4iGS178icr">/spaces/lFokgwgJiwLXu7G8MVSJ/pages/YzI8PWWyMC4iGS178icr</a></td><td><a href="/files/Evc5m2Ay0xQkIILSQHay">/files/Evc5m2Ay0xQkIILSQHay</a></td></tr></tbody></table>

Once the provider is configured, enable it on the enrolment form you want. See [Enrolment form](/guides-enrolment/enrolment/enrolment-form) for form settings.

#### Geo and market considerations (which providers to offer)

Provider choice is often regional. Offer the buttons your customers already use.

Sign in with Apple is a strong default in iOS-heavy markets. Google Sign-In is a strong default in Android-heavy markets. Google can be constrained where services are restricted. LINE Login is especially relevant in Japan, Taiwan, and Thailand.

If you operate across countries, keep it simple. Use **separate enrolment forms per region**. Enable only the relevant providers on each form. This avoids confusing users with unused buttons.

#### What data you get

You can expect an **email** from each provider. First name and last name are provider-dependent. Treat names as optional.

Design your matching rules as if you only get email over time. Apple can return names only once. Apple can also return relay emails. See [Apple Sign-in configuration](/guides-enrolment/enrolment/enrolment-form/social-sign-in/apple-sign-in) for those behaviors.

{% hint style="info" %}
Facebook does not always return an email. Some accounts do not have a usable email, and some setups do not request it. Keep a fallback like “Continue with email”.
{% endhint %}

### FAQ

<details>

<summary><strong>Can the same user sign in with different providers?</strong></summary>

Yes, but the result depends on what you use as the matching key. Most setups match on email.

If Apple and Google return the **same email**, they resolve to the same profile. If they return different emails, you can create duplicates. This happens often with Apple relay emails, work vs personal emails, or users changing provider settings.

Avoid duplicates by linking identities in your CRM. Store the provider identifier (for example, the provider subject) against the customer when you can. Use a second identifier for matching when email is not stable. Common choices are loyalty ID, phone, or a one-time code.

</details>

<details>

<summary><strong>Do we still need email verification?</strong></summary>

Usually no, because the provider verifies the email.

Keep email verification when you need an extra assurance step. Common cases are high-value accounts and regulated programs. Another common pattern is step-up verification only when risk is high. Example: social sign-in for enrolment, then OTP verification before account changes or rewards redemption.

</details>

<details>

<summary><strong>How should we handle Apple “Hide My Email”?</strong></summary>

Treat Apple relay emails as valid emails. They can still receive messages. Do not assume they match the email in your CRM.

If you already have customers in another system, avoid “email only” matching for Apple-heavy audiences. Add a second identifier in the flow. Use a membership number, phone number, or a one-time code. You can also let the user confirm a known identifier after sign-in before you load an existing profile.

</details>

<details>

<summary><strong>What happens if the user cancels social sign-in or the provider fails?</strong></summary>

The user stays unauthenticated. The form should fall back to your alternate entry path. A common fallback is “Continue with email”.

Keep the error message specific. Use wording like “Sign-in was canceled” or “Sign-in failed”. Avoid ambiguous messages like “Something went wrong”. If you see frequent failures, check third‑party cookie settings, pop-up blockers, and the authorized redirect origins configured at the provider.

</details>

<details>

<summary><strong>Can we limit which providers appear (by country or by device)?</strong></summary>

Yes. Keep the button set minimal for each audience. Offer the providers your users already use in that market.

If you operate in multiple countries, use separate enrolment forms per region. Enable only the relevant providers on each form. If you want device-specific UX, keep Apple prominent on iOS and Google prominent on Android, but still provide a fallback path for users who do not want to use social sign-in.

</details>


# Google Sign-in configuration

Configure Google Sign-In (OAuth 2.0 Client ID) and connect it to The Wallet Crew social sign-in.

Use this when you want to enable the **Google** button in an enrolment form.

Start with [Social sign-in](/guides-enrolment/enrolment/enrolment-form/social-sign-in) to understand the user flow. Then come back here for the provider setup.

<div data-with-frame="true"><figure><img src="/files/BUn9l4M9E7WjzL90YhPE" alt="Google-Social-Sign-In-Example" width="375"><figcaption><p>Connect with Google in an enrolment form example</p></figcaption></figure></div>

### Overview

#### What you’ll set up

* A **Google OAuth 2.0 Client ID**.
* **Authorized JavaScript origins** for your enrolment form domains.
* The Client ID stored in **The Wallet Crew** admin console.

#### Prerequisites

* Access to your brand’s **Google Cloud Console** project.
* Permission to create **OAuth 2.0 Client IDs**.
* The list of domains where your enrolment forms will run (prod + staging + dev + custom).

### Configure Sign in with Google

{% stepper %}
{% step %}

#### **Open Credentials**

Open the Google Cloud Console **Credentials** page:

<p align="center"><a href="https://console.developers.google.com/apis/credentials" class="button secondary" data-icon="chevrons-right">Google Credential page</a></p>
{% endstep %}

{% step %}

#### **Create a Web application OAuth client**

1. Click `Create credentials` → `OAuth client ID`.
2. Choose application type: `Web application`.
3. Set a name. Example: `neostore login`.
   {% endstep %}

{% step %}

#### **Configure origins**

Add **Authorized JavaScript origins** for every domain you will use.

* `https://app.neostore.cloud`
* `https://app-qa.neostore.cloud`
* `https://app-dev.neostore.cloud`
* Any **custom domain** you use for enrolment forms (add the exact origin).

Leave **Authorized redirect URIs** empty.

![Google OAuth client settings](/files/KFbbe6M1LKQ8elJ0hON0)

![Wallet Crew Google social login settings](/files/XEm6yQR7Z38aKHGsC4TL)
{% endstep %}
{% endstepper %}

{% hint style="info" %}
Google Sign-In for web uses the **Client ID**. It’s safe to paste it in the admin console.

Do not share any Google **client secret**. You should not need one for this flow.
{% endhint %}

### Configure Google in The Wallet Crew

1. Open **Social logins → Google** in the admin console.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/settings/social/google" class="button secondary" data-icon="chevrons-right">Social logins -> Google</a></p>

<div data-with-frame="true"><figure><img src="/files/NM18rYjHnkE9cIPevK7t" alt="The Wallet Crew - Google Social Sign In configuration" width="563"><figcaption><p>The Wallet Crew - Google Social Sign In configuration</p></figcaption></figure></div>

2. Paste the **Client ID** from Google.
3. Save.

### Enable Google on your enrolment form

Enable the provider in the enrolment form settings.

Go into `advanced configuration -> Layout` Open the layout you want to activate social sign-in on and add these lines

```yaml
signinOptions:
  providers:
    - type: android
      displayProps:
        isMobile: true
        isAndroid: true
```

For more information see [Enrolment form](/guides-enrolment/enrolment/enrolment-form).

### FAQ

<details>

<summary><strong>Do we need a Google client secret?</strong></summary>

No. This setup uses the **Google Client ID** only.

If you see a client secret in Google Cloud Console, don’t paste it anywhere in Wallet Crew.

</details>

<details>

<summary><strong>Should we configure “Authorized redirect URIs” in Google?</strong></summary>

No. Leave **Authorized redirect URIs** empty for this flow.

If you add redirect URIs, it usually doesn’t help. It can also confuse debugging later.

</details>

<details>

<summary><strong>What exactly must be added as an “Authorized JavaScript origin”?</strong></summary>

Add the **origin only**: `scheme://host` (and port if you use one).

Examples:

* ✅ `https://app.neostore.cloud`
* ✅ `https://brand.example.com`
* ❌ `https://app.neostore.cloud/molia/mobile` (paths are not allowed)

</details>

<details>

<summary><strong>We use a custom domain. What should we do?</strong></summary>

Add your custom domain as an **Authorized JavaScript origin** in Google Cloud Console.

Use the exact domain users see in the browser. Example: `https://wallet.brand.com`.

</details>

<details>

<summary><strong>Why do we list prod, QA, and dev origins?</strong></summary>

Google validates the origin at runtime.

If a user hits QA but only prod is configured, Google rejects the sign-in.

</details>

<details>

<summary><strong>Where do we enable the Google button in the user journey?</strong></summary>

Provider setup is not enough. You must also enable Google on the enrolment form.

See [Social sign-in](/guides-enrolment/enrolment/enrolment-form/social-sign-in) and [Enrolment form](/guides-enrolment/enrolment/enrolment-form).

</details>


# Apple Sign-in configuration

Configure Sign in with Apple and connect it to The Wallet Crew social sign-in.

Use this when you want to enable the **Apple** button in an enrolment form.

Start with [Social sign-in](/guides-enrolment/enrolment/enrolment-form/social-sign-in) to understand the user flow. Then come back here for the provider setup.

<figure><img src="/files/QNDF5EHPRT2gnicaQUyx" alt="Apple-Social-Sign-In-Example" width="375"><figcaption><p>Connect with Apple in an enrolment form example</p></figcaption></figure>

### Overview

Use this page to configure **Sign in with Apple** (Apple ID login) for **The Wallet Crew** enrolment forms.

You will configure Apple in two places:

1. **Apple Developer**: App ID + Service ID + domains + return URLs.
2. **The Wallet Crew admin**: paste your Apple **Service ID**.

#### Terminology (Apple)

These terms are used in Apple Developer and OAuth setups.

* **App ID**: identifies your app. Uses a **Bundle ID** like `com.brand.app`.
* **Service ID**: identifies a web sign-in integration. This is what you paste in The Wallet Crew.
* **Domains and subdomains**: where the enrolment form is hosted.
* **Return URLs**: OAuth / OpenID Connect callback URLs used after Apple login.

#### Prerequisites

* Access to your brand’s **Apple Developer** account.
* Permission to manage **Identifiers** and **Service IDs**.
* The list of domains where your enrolment forms will run (prod + staging + dev + custom).

#### Apple behavior notes

Sign in with Apple has a few behaviors that impact your enrolment journey and your matching rules.

On the **first sign-in** with a given Apple account, Apple can provide **first name**, **last name**, and **email**. On **subsequent sign-ins**, Apple typically returns **email only**. Plan your forms as if you will only have the email long term.

{% hint style="warning" %}
Apple users can enable **Hide My Email**. In that case, Apple returns a relay address instead of the user’s real email.

That relay email can create duplicates if your CRM expects another identifier. If you email customers, you may also need to support delivery to Apple relay addresses.
{% endhint %}

Apple’s reference: [Communicating Using the Private Email Relay Service](https://developer.apple.com/documentation/signinwithapple/communicating-using-the-private-email-relay-service/).

### Configure Sign in with Apple

{% stepper %}
{% step %}

#### **Open Identifiers**

1. Log in to the Apple Developer account.

<p align="center"><a href="https://developer.apple.com/account" class="button secondary" data-icon="chevrons-right">Developer Account</a></p>

2. Go to `Certificates, IDs & Profiles` → `Identifiers`.
   {% endstep %}

{% step %}

#### **Create (or reuse) an App ID**

1. Click `+` and select `App IDs`.

![Click on +](/files/J73nX6HF1rOw3EVZeoIq) ![Select App ID](/files/xz0levkO3403dIBuSShI)

> If you already have an App ID for the same domain/app, you may be able to reuse it. This can unlock advanced scenarios. If you’re unsure, ask The Wallet Crew team.

2. Select the `App` type.
3. Fill the form with:
   1. **Description**: a meaningful name for your project
   2. **Bundle ID**: use the value provided by The Wallet Crew (example: `cloud.neostore.molia.app`)
   3. **Capabilities**: enable `Sign In with Apple`

<div><figure><img src="/files/aNXljXSJIrmcQ4wVCp5n" alt="Description and Bundle ID" width="520"><figcaption></figcaption></figure> <figure><img src="/files/BKDeUVkA39laMxEkrm3J" alt="Capabilities" width="563"><figcaption></figcaption></figure></div>

4. Validate the form and click `Register`.

<figure><img src="/files/W9QtdHO4FzabdpgWjSZw" alt="Create (or reuse) an App ID"><figcaption></figcaption></figure>
{% endstep %}

{% step %}

#### **Create (or reuse) a Service ID**

You need a **Service ID** for Sign in with Apple on the web.

1. In the identifier list, switch the filter to `Service IDs`.
2. Click `+` and select `Service IDs`.

<div><figure><img src="/files/J73nX6HF1rOw3EVZeoIq" alt="Click on +" width="420"><figcaption><p>Click on +</p></figcaption></figure> <figure><img src="/files/wCnMijc8b8NQrCU5Iynt" alt="Service ID" width="563"><figcaption><p>Service ID</p></figcaption></figure></div>

3. Fill the form with:
   1. **Description**: a meaningful name for your service
   2. **Identifier**: use the value provided by The Wallet Crew (example: `cloud.neostore.molia.service`)

<figure><img src="/files/u5TGZvX4BHrxqQMbDjWv" alt="Identifier"><figcaption></figcaption></figure>

4. Validate the form and click `Register`.

{% hint style="info" %}
The **Service ID identifier** is the value you will paste in The Wallet Crew admin.
{% endhint %}
{% endstep %}

{% step %}

#### **Configure Sign in with Apple (domains + return URLs)**

1. On the identifier list, select the Service ID you just created.
2. Enable `Sign in with Apple` and click `Configure`.

<figure><img src="/files/Zf8aqPCAyJfRfShQJ40E" alt="Configure Sign in with Apple (domains + return URLs)"><figcaption></figcaption></figure>

3. Fill the form with:
   1. **Primary App ID**: the App ID you created earlier (example: `cloud.neostore.molia.app`)
   2. **Domains and subdomains**: add all domains that will host your enrolment forms (prod + staging + dev + custom)
   3. **Return URLs**: add the OAuth callback URL(s) for each environment

<figure><img src="/files/JCq3ZdfvBA1JIvzHEuQb" alt="Return URLs"><figcaption></figcaption></figure>

4. Validate the form and click **Continue**.

{% hint style="warning" %}
Apple is strict here. Use the exact values.

If you are unsure about the callback URL format, ask The Wallet Crew team.
{% endhint %}
{% endstep %}

{% step %}

#### Configure Email Communication Domains

This step is required if your app sends emails to users who selected **Hide My Email** when signing in with Apple.

Apple generates a relay address like:

> <randomstring@privaterelay.appleid.com>

You must register your sending domain, or Apple will reject those emails. Treat relay addresses like normal email addresses in your backend.

{% hint style="info" %}
This step is required if you send email to users who chose **Hide My Email**.

Apple returns a **relay email address**. Treat it like a real mailbox.
{% endhint %}

**Open the Services section**

* In **Certificates, Identifiers & Profiles**, click **Services** in the left menu.
* Click **Sign in with Apple for Email Communication**.
* Click **Configure**.

<figure><img src="/files/9qOZgJRdAU2wCTDiS1rh" alt="Configure"><figcaption></figcaption></figure>

* Under **Email Sources**, click the **+** button to add a new email source.

<figure><img src="/files/iIbmsIPXQZUbPa0432gh" alt="Email Sources"><figcaption></figcaption></figure>

**Fill the form with:**

* **Domains and Subdomains**:\
  Add the domain(s) you send email from.\
  Example:

  ```
  myapp.com
  mail.myapp.com
  ```
* **Email Addresses**:\
  Add the sender email address(es) used by your application.\
  Example:

```
noreply@myapp.com
support@myapp.com
```

<figure><img src="/files/51uEQz7nDFl9YtWtWOsY" alt="Fill the form with"><figcaption></figcaption></figure>

* Click **Next** and complete validation (SPF/DKIM verification if required).
  {% endstep %}
  {% endstepper %}

### Configure Apple in The Wallet Crew

1. On The Wallet Crew administration console, open:

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/settings/social/apple" class="button secondary" data-icon="chevrons-right">Social Login → Apple</a></p>

<div data-with-frame="true"><figure><img src="/files/6zUdnHYv03icvb4WEy00" alt="The Wallet Crew - Apple Social Sign In configuration" width="563"><figcaption><p>The Wallet Crew - Apple Social Sign In configuration</p></figcaption></figure></div>

2. Fill the **Service ID** with the identifier used when creating the Service ID (example: `cloud.neostore.molia.service`).
3. Save.

{% hint style="info" %}
Paste the **Service ID** identifier.

Do not paste the App ID name or the Bundle ID.
{% endhint %}

### Enable Apple on your enrolment form

Enable the provider in the enrolment form settings.

Go into `advanced configuration -> Layout`. Open the layout to activate social sign-in on and add these lines:

```yaml
signinOptions:
  providers:
    - type: apple
      displayProps:
        isMobile: true
        isIOS: true
```

For more information see [Enrolment form](/guides-enrolment/enrolment/enrolment-form).

### FAQ

<details>

<summary>Which domains do I need to add in Apple Developer?</summary>

Add every domain that can host the enrolment form.

Include prod, staging, dev, and any custom domain.

</details>

<details>

<summary>What should I put in “Return URLs”?</summary>

Add the callback URL for each environment and each form domain.

Keep it exact. Scheme, path, and trailing slash must match.

</details>

<details>

<summary>Why do I only get the user’s email after the first login?</summary>

Apple only returns name fields on the first consent.

On later logins, Apple typically returns email only.

</details>

<details>

<summary>What is “Hide My Email” and what does it change?</summary>

Apple may return a relay email instead of the user’s real email.

That can create duplicates if you match users by email only.

Apple’s reference: [Communicating Using the Private Email Relay Service](https://developer.apple.com/documentation/signinwithapple/communicating-using-the-private-email-relay-service/){target="\_blank"}.

</details>

<details>

<summary>Which value do I paste in The Wallet Crew admin: Bundle ID, App ID, or Service ID?</summary>

Paste the **Service ID**.

Example: `cloud.thewalletcrew.molia.service`.

</details>


# LINE Sign-in configuration

Configure LINE Login and connect it to The Wallet Crew social sign-in.

Use this when you want to enable the **LINE** button in an enrolment form.

Start with [Social sign-in](/guides-enrolment/enrolment/enrolment-form/social-sign-in) to understand the user flow. Then come back here for the provider setup.

<div data-with-frame="true"><figure><img src="/files/1K4g7puLRH6mNcTsy5vG" alt="Line-Social-Sign-In-Example" width="375"><figcaption><p>Connect with Line in an enrolment form example</p></figcaption></figure></div>

### Overview

#### What you'll set up

* A **Line Channem** with the Line Login product enabled.
* **Allowed OAuth redirect URIs** and **valid domains** for your enrolment form.
* The App ID stored in **The Wallet Crew** admin console.

#### Prerequisites

* Access to your **LINE Developers Console**.
* Permission to create and manage **channels**.
* The list of domains where your enrolment forms will run (prod + staging + dev + custom).

### Create the LINE channel

{% stepper %}
{% step %}

#### **Create a provider and channel**

Go to the LINE Developers Console

<p align="center"><a href="https://developers.line.biz/console" class="button secondary" data-icon="chevrons-right">Line Developer Console</a></p>

1. Select or create a **Provider**
2. Click **Create a new channel**
   {% endstep %}

{% step %}

#### **Select LINE Login**

![Select LINE Login](/files/vgRgnGXXJKAwQSgOp7dw)

1. Choose **LINE Login**
2. Select app type: **Web app**
3. Fill the required information
4. Create the channel
   {% endstep %}

{% step %}

#### **Enable Email permission (OpenID Connect)**

Open your channel settings:

![Enable Email permission (OpenID Connect)](/files/0pWZyilsNX2RkzZ9amaw)

1. Go to the **OpenID Connect** section
2. Enable **Email address permission**

This step is required if your enrolment flow depends on email.
{% endstep %}

{% step %}

#### **Configure callback URLs**

In the **LINE Login** tab:

Add a callback URL for each environment:

```http
https://app.neostore.cloud/auth/callback/line
https://app-qa.neostore.cloud/auth/callback/line
https://app-dev.neostore.cloud/auth/callback/line
https://<your-custom-domain>/auth/callback/line
```

Important:

* The full URL must match exactly
* Include `/auth/callback/line`
* Add prod + QA + dev + custom domains

Save your changes.
{% endstep %}

{% step %}

### Publish your channel

In the top-left corner, click **Developing**.

<figure><img src="/files/gmRuGpU1uaIoSvfDjYBd" alt=""><figcaption></figcaption></figure>

Then click **Publish** to make the channel available for production use.
{% endstep %}
{% endstepper %}

### Configure LINE in The Wallet Crew

In The Wallet Crew Backoffice, open the LINE configuration page.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/settings/social/line" class="button secondary" data-icon="chevrons-right">Social Login -> Line</a></p>

<div data-with-frame="true"><figure><img src="/files/jhtQ9aL7LLrLDP5kkQ1w" alt="The Wallet Crew - Line configuration screen" width="563"><figcaption><p>Line configuration screen</p></figcaption></figure></div>

Copy the values from the LINE Developers Console into The Wallet Crew.

After saving, keep this page open for a quick cross-check:

* The LINE channel must be the same one used for the callback URLs.
* The saved `clientId` must match the **Channel ID** exactly.

{% hint style="info" %}
You can find these values in:

LINE Developers Console → Your channel → **Basic settings**
{% endhint %}

### Enable LINE on your enrolment form

Enable the provider in the enrolment form settings.

Go into `advanced configuration -> Layout`. Open the layout to activate social sign-in on and add these lines:

<pre class="language-yaml"><code class="lang-yaml"><strong>signinOptions:
</strong>  providers:
    - type: line
</code></pre>

For more information see [Enrolment form](/guides-enrolment/enrolment/enrolment-form).

### FAQ

<details>

<summary>Which LINE channel type should I create for this setup?</summary>

Create a **LINE Login** channel with app type **Web app**.

That’s the channel type that supports the OAuth callback flow used by enrolment forms.

</details>

<details>

<summary>Do I need to enable “Email address permission” in OpenID Connect?</summary>

Enable it if your enrolment flow requires an email.

Without it, LINE may not return an email for the user.

</details>

<details>

<summary>What callback URLs do I need to add?</summary>

Add one callback URL per environment.

The URL must match exactly and must include `/auth/callback/line`.

Use the patterns listed above for prod, QA, dev, and any custom domain.

</details>

<details>

<summary>Where do I find the LINE <code>clientId</code> ?</summary>

In the LINE Developers Console:

**Your channel → Basic settings**.

Copy the **Channel ID** into `authentication.clientId`.

</details>

<details>

<summary>How do I actually show the LINE button on the enrolment form?</summary>

Enable the provider in your **enrolment form settings**.

If you manage buttons via layout YAML, add `- type: line` under `signinOptions.providers`.

</details>


# Facebook Sign-in configuration

Configure Facebook Login for enrolment forms: create a Facebook App, set redirect URIs and allowed domains, then add the App ID in The Wallet Crew admin console.

Use this when you want to enable the **Facebook** button in an enrolment form.

Start with [Social sign-in](/guides-enrolment/enrolment/enrolment-form/social-sign-in) to understand the user flow. Then come back here for the provider setup.

<div data-with-frame="true"><figure><img src="/files/Evc5m2Ay0xQkIILSQHay" alt="FB-Social-Sign-In-Example" width="375"><figcaption><p>Connect with Facebook in an enrolment form example</p></figcaption></figure></div>

### Overview

#### What you'll set up

* A **Facebook App** with the Facebook Login product enabled.
* **Allowed OAuth redirect URIs** and **valid domains** for your enrolment form.
* The App ID stored in **The Wallet Crew** admin console.

#### Prerequisites

* Access to your brand's **Meta for Developers** account.
* Permission to create or manage **Facebook Apps**.
* The list of domains where your enrolment forms will run (prod + staging + dev + custom).

### Create the Facebook App

{% stepper %}
{% step %}

#### **Open the Meta Developer portal**

Go to the Meta for Developers Apps dashboard:

<p align="center"><a href="https://developers.facebook.com/apps" class="button secondary" data-icon="chevrons-right">Meta Apps Dashboard</a></p>
{% endstep %}

{% step %}

#### **Create a new App**

1. Click `Create App`.
2. Select use case: `Authenticate and request data from users` (or `Consumer` depending on your Meta dashboard version).
3. Set a name. Example: `neostore login`.
4. Complete the app creation wizard and confirm your developer account if prompted.
   {% endstep %}

{% step %}

#### **Add the Facebook Login product**

1. From your App dashboard, find the **Add a product** section.
2. Click `Set up` on **Facebook Login for Business** (or **Facebook Login**).
3. Choose `Web` as the platform.
4. Enter your website URL (e.g. `https://app.neostore.cloud`) and save.
   {% endstep %}

{% step %}

#### **Configure allowed domains and redirect URIs**

Navigate to **Facebook Login → Settings** in the left sidebar and configure the following:

**Valid OAuth Redirect URIs** — add one URI per environment:

* `https://app.neostore.cloud`
* `https://app-qa.neostore.cloud`
* `https://app-dev.neostore.cloud`
* Any **custom domain** you use for enrolment forms (add the exact origin).

**Allowed Domains for the JavaScript SDK** — add the same list of origins (scheme + host only, no paths).

Save your changes.

> **Note:** Unlike Google, Facebook requires both the redirect URI and the domain allowlist to be filled in.
> {% endstep %}

{% step %}

#### **Switch the App to Live mode**

1. In the top bar of the App dashboard, toggle the app from **Development** to **Live**.
2. If prompted, provide a **Privacy Policy URL** — this is required by Meta before going live.

> While in Development mode, only users listed as testers or developers on the app can sign in. Switch to Live so all users can authenticate.
> {% endstep %}
> {% endstepper %}

> **Info:** Facebook Sign-In for web uses only the **App ID**. It is safe to paste it in the admin console.

### Add the App ID in The Wallet Crew

1. Open **Social logins → Facebook** in the admin console.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/settings/social/facebook" class="button secondary" data-icon="chevrons-right">Social logins -> Facebook</a></p>

<div data-with-frame="true"><figure><img src="/files/kYQi6mDfv0HHY0VoD9EP" alt="The Wallet Crew - Facebook Social Sign In configuration" width="563"><figcaption><p>The Wallet Crew - Facebook Social Sign In configuration</p></figcaption></figure></div>

2. Paste the **App ID** from Meta for Developers.
3. Pas the **App Secret** from Meta for Developers.
4. Save.

### Enable Facebook on your enrolment form

Enable the provider in the enrolment form settings.

Go into `advanced configuration -> Layout` Open the layout you want to activate social sign-in on and add these lines

<pre class="language-yaml"><code class="lang-yaml"><strong>signinOptions:
</strong>  providers:
    - type: facebook
</code></pre>

For more information see [Enrolment form](/guides-enrolment/enrolment/enrolment-form).

### FAQ

<details>

<summary><strong>Do we need a Facebook App Secret?</strong></summary>

No. This setup uses the **App ID** only.

If you see an App Secret in Meta for Developers, don't paste it anywhere in Wallet Crew.

</details>

<details>

<summary><strong>Should we configure "Authorized redirect URIs" in Facebook?</strong></summary>

Yes — unlike Google, Facebook **requires** valid OAuth Redirect URIs to be explicitly listed.

Add each environment origin under **Facebook Login → Settings → Valid OAuth Redirect URIs**.

</details>

<details>

<summary><strong>What exactly must be added as an allowed domain?</strong></summary>

Add the **origin only**: `scheme://host` (and port if you use a non-standard one).

Examples:

* ✅ `https://app.neostore.cloud`
* ✅ `https://brand.example.com`
* ❌ `https://app.neostore.cloud/molia/mobile` (paths are not allowed)

</details>

<details>

<summary><strong>We use a custom domain. What should we do?</strong></summary>

Add your custom domain both to **Valid OAuth Redirect URIs** and **Allowed Domains for the JavaScript SDK** in the Facebook Login settings.

Use the exact domain users see in the browser. Example: `https://wallet.brand.com`.

</details>

<details>

<summary><strong>Why do we list prod, QA, and dev origins?</strong></summary>

Facebook validates the origin at runtime.

If a user hits QA but only prod is configured, Facebook rejects the sign-in.

</details>

<details>

<summary><strong>Where do we enable the Facebook button in the user journey?</strong></summary>

Provider setup is not enough. You must also enable Facebook on the enrolment form.

See [Social sign-in](/guides-enrolment/enrolment/enrolment-form/social-sign-in) and [Enrolment form](/guides-enrolment/enrolment/enrolment-form).

</details>


# Design

Customize enrolment forms with brand logos, colors, typography, subtitles, and header images.

## Design The Wallet Crew Registration Form

#### Design Capacities of The Wallet Crew Registration Form

The Wallet Crew registration form is designed with flexibility and customizability in mind, utilizing the Material-UI (MUI) theming system. Below are the design elements and their customization options.

**Material-UI Theming System**

The application leverages the Material-UI theming system, allowing for comprehensive customization. For more details, refer to the [MUI Theming Documentation](https://mui.com/customization/theming/).

#### Logo

The logo can be customized to represent your brand identity. Ensure the logo fits well within the registration form’s layout and maintains visibility across different devices.

#### Colors

The color scheme is a crucial aspect of the registration form’s design. The following images illustrate the color options:

![Colors](/files/XUiv6emy2e476SYvWnPP)

![Colors (2)](/files/z1BibD5byScSI517dnZ5)

These color schemes can be adapted to match your brand’s palette using the MUI theming system.

#### Typography

Typography settings are configurable to ensure consistency with your brand’s visual identity. The following image illustrates the typography options:

![Typography](/files/kZLhyPHfzDtfAFI85zEY)

Adjust fonts, sizes, and weights through the MUI theming system to align with your brand guidelines.

#### Subtitle

The subtitle is an optional text field where you can offer an incentive or call to action for users to sign up. Examples include:

* Get 10% off
* Receive news from \[tenant name]
* Join now!

This field should be concise and compelling to encourage user registration.

#### Header Image

The header image enhances the visual appeal of the registration form. This image can be specified in two ways:

1. As a URL: `HeaderImageConfiguration.Url`
2. As a `HeaderImageConfiguration` object

The image is displayed using the following CSS properties:

* `background-size: cover`
* `height: 200px`

The width is responsive, adjusting to the device’s screen width with a minimum width of 280px and approximately 400px on modern smartphones. Additional styles can be applied using the `HeaderImageConfiguration.AdditionalStyles` property.

#### Theme Palette

The registration form supports both dark and light themes. Choose the theme that best aligns with your brand’s look and feel.

By customizing these elements, you can create a registration form that is visually appealing and consistent with your brand identity. For further customization, refer to the [MUI Theming Documentation](https://mui.com/customization/theming/).


# Validation rules

Configure enrolment form validation rules for required, format, and matching checks.

Validation rules protect data quality at the point of capture. They prevent incomplete or incorrectly formatted values from entering customer profiles and downstream systems.

Choose rules based on the purpose of each field. Strict validation is useful for identifiers. Optional enrichment fields should remain easy to complete.

<details>

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

* A loyalty programme requires an email address and verifies its format before enrolment.
* A ticketing form limits a booking reference to the expected character length.
* A membership form compares the confirmation email against the original email field.

</details>

### How validation works

Validation is configured at the individual field level. Each rule checks whether a value meets the data requirements before the form is submitted.

Use a small number of rules that match the field’s purpose. Overly restrictive forms can increase abandonment and create support work.

### Available validation rules

#### Required

* Indicates whether the field must be filled out.
* For checkboxes and switchboxes, this means the box must be checked.

#### `minLength`

* Defines the **minimum number of characters** required for a field's value.
* Useful for fields like names or identification numbers.

#### `maxLength`

* Sets the **maximum number of characters** allowed in the field.
* Helps prevent excessively long inputs that could disrupt layout or storage.

#### `email`

* Combines two layers of validation:
  1. **Regular Expression Check**: Uses the following default regex to validate format:

     ```js
     /^[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\.)+[a-zA-Z0-9](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?$/
     ```

     This regex can be **overridden** with a custom one if needed.
  2. **Domain Check via DNS**: The Wallet Crew verifies that the email domain accepts mail by checking for **MX records**.

#### `phone`

* Validates phone numbers using the [react-phone-number-input](https://catamphetamine.gitlab.io/react-phone-number-input/) component.
* This is based on Google’s international phone number validation library.
* Ensures numbers are correctly formatted and country codes are recognized.

#### `expression`

* Allows administrators to define a **custom regular expression** to validate the field.
* Flexible option for enforcing format-specific data (e.g., postal codes, IDs).

#### `equality`

* Compares the field’s value to:
  * Another field’s value (e.g., "Confirm Password")
  * A static constant value
* Ensures consistency and matching where required.

### Configure rules effectively

Start with the minimum needed to identify a customer and issue a pass. Add more rules only when they improve an operational or compliance outcome.

* Use `required` only for information needed during enrolment.
* Use `email` and `phone` for customer contact identifiers.
* Use `equality` for confirmation fields, such as repeated email addresses.
* Test custom regular expressions with expected and invalid values before publishing.

{% hint style="warning" %}
Customize the default email expression only when there is a documented requirement. An overly narrow expression can reject valid customer email addresses.
{% endhint %}

### Validate the form before publishing

Submit the form with representative valid and invalid values. Confirm that required fields block empty submissions, format rules show clear errors, and equality fields reject mismatched values.

Review the result on mobile as well as desktop. Most enrolment journeys begin on a phone after a QR-code scan or campaign link.

### FAQ

<details>

<summary><strong>Which fields should be required?</strong></summary>

Require only fields needed to identify the customer, issue the pass, or meet a documented compliance requirement. Optional fields can be collected later.

</details>

<details>

<summary><strong>When should an expression rule be used?</strong></summary>

Use an expression rule when a business identifier requires a specific format that the standard rules do not cover. Test the expression against valid and invalid sample values before publishing.

</details>

<details>

<summary><strong>Can an email address be confirmed?</strong></summary>

Yes. Add a second email field and apply the `equality` rule to compare it with the original field.

</details>

<details>

<summary><strong>Why does a valid-looking email address fail validation?</strong></summary>

The email rule checks both the address format and whether the domain accepts mail through MX records. Confirm that the domain is spelled correctly and has valid mail records.

</details>


# Cloudflare Turnstile

Enhance enrolment security with Cloudflare Turnstile to verify human traffic.

Cloudflare Turnstile can be enabled to reduce automated enrolments and scripted abuse. When enabled, the enrolment form includes a Turnstile check and validates the resulting token server-side.

The implementation stays mostly invisible. Turnstile runs in the background and only becomes interactive when Cloudflare requires extra verification.

{% hint style="warning" %}
Bot detection cannot be 100% accurate. Turnstile provides basic bot mitigation, not a guarantee. AI-assisted automation and human-in-the-loop services make abuse increasingly hard to fully control. Cloudflare documents Turnstile’s approach here: [Cloudflare Turnstile docs](https://developers.cloudflare.com/turnstile/).
{% endhint %}

<div data-with-frame="true"><figure><img src="/files/NMx4pZhGspSLSmHgt8Pl" alt="Turnstile challenge displayed as a modal during enrolment" width="375"><figcaption><p>Extra verification needed</p></figcaption></figure></div>

## How it works

1. When the enrolment form loads, Turnstile runs in the background.
2. When the form is submitted, Turnstile may ask for an interactive check.
3. The Wallet Crew validates the Turnstile token server-side before accepting the enrolment.

## Configuration

Configuration requires a Turnstile widget in Cloudflare and the widget keys. The Wallet Crew uses the **Site key** and **Secret key** to validate enrolment submissions.

{% stepper %}
{% step %}

### Create and configure a Turnstile widget in Cloudflare

Create a Turnstile widget in the Cloudflare dashboard. Cloudflare provides a **Site key** (public) and a **Secret key** (private) for each widget.

* Official setup guide: [Cloudflare Turnstile “Get started”](https://developers.cloudflare.com/turnstile/get-started/)
* Cloudflare dashboard entry point: [dash.cloudflare.com](https://dash.cloudflare.com/) (then open **Turnstile**)

**The default configuration is usually sufficient. Please consult your IT team for any additional adjustments.**
{% endstep %}

{% step %}

### Retrieve the Site key and Secret key

In Cloudflare, open the widget configuration and copy:

* **Site key**
* **Secret key**

These values are required in The Wallet Crew Back Office.
{% endstep %}

{% step %}

### Enable Turnstile in The Wallet Crew

Ask The Wallet Crew team to enable the Cloudflare Turnstile extension for the tenant.

Then open the Back Office settings page and paste the keys:

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/settings/security/turnstile" class="button secondary" data-icon="chevrons-right">Turnstile settings</a></p>

<div data-with-frame="true"><figure><img src="/files/E439fhUYJ6OXyu0s5bg7" alt="Turnstile settings in the Back Office." width="563"><figcaption><p>Turnstile settings in the Back Office.</p></figcaption></figure></div>
{% endstep %}
{% endstepper %}

## Notes

Turnstile is usually invisible because it runs in the background. An interactive check is only shown when Cloudflare flags the session as higher risk.

Token validation is always performed server-side by The Wallet Crew when the extension is enabled.

### Limits and expectations

Turnstile improves baseline protection, but it does not “solve bots”. Automated abuse evolves quickly and often relies on AI-assisted tooling, residential proxies, and human-in-the-loop services. This makes perfect bot detection unrealistic for most public enrolment flows.

Cloudflare positions Turnstile as a frictionless alternative to CAPTCHAs, not as a guarantee that every bot will be blocked. Combine Turnstile with other controls when enrolment is business-critical.

Official documentation: [Cloudflare Turnstile docs](https://developers.cloudflare.com/turnstile/)

### Challenge cookie

After a successful Turnstile verification, the application can set a short-lived security cookie. This keeps bot-protection state between requests and reduces repeated Turnstile challenges during the same enrolment session.

How this cookie works:

1. The user submits the enrolment form with a valid Turnstile token.
2. The server validates that token with Cloudflare.
3. If validation succeeds, the server issues a signed proof cookie.
4. On the next enrolment-related requests, the server checks that cookie.
5. If the cookie is still valid, the server can skip a new Turnstile challenge for that short window.

This behavior is configurable in Back Office:

* Cookie validity is set in seconds, common value is 600 seconds (10 minutes)&#x20;
* When disabled, the server does not issue this cookie and Turnstile verification is required for each submission path.

#### Legal requirement: security cookie

This cookie should be listed in the cookie policy (often under “strictly necessary” / “security cookies”).

* Cookie name: `neo.<tenantId>.turnstile-proof` where `<tenantId>` is the identifier of your wallet crew tenant
* Purpose: Keep bot-protection state between requests and avoid repeated Turnstile challenges
* Category: Security cookie (generally considered strictly necessary)
* Lifetime: Configurable (seconds). Set to 0 to disable.
* Scope: Enrolment form submission
* Technical attributes:
  * `HttpOnly`
  * `Secure`
  * `SameSite=Lax`
  * `Path=/`

This cookie is used only for security and fraud prevention, not for analytics or marketing.

## FAQ

<details>

<summary>Does Turnstile always show a CAPTCHA-like challenge?</summary>

No. Turnstile often completes in the background. An interactive widget is only displayed when Cloudflare requires extra verification.

</details>

<details>

<summary>Is Turnstile enough to fully block bots?</summary>

No. Turnstile provides baseline bot mitigation, but it is not perfect. Modern abuse can use AI-assisted automation, proxy networks, and human-in-the-loop solving.

Cloudflare’s official documentation covers Turnstile’s intent and behavior: [Cloudflare Turnstile docs](https://developers.cloudflare.com/turnstile/).

</details>

<details>

<summary>Which keys are needed from Cloudflare?</summary>

The Wallet Crew requires the Turnstile widget **Site key** and **Secret key**.

Cloudflare explains how to create a widget and retrieve those values here: [Turnstile “Get started”](https://developers.cloudflare.com/turnstile/get-started/).

</details>

<details>

<summary>What happens if the Turnstile token is missing or invalid?</summary>

When the extension is enabled, the enrolment submission is only accepted when a valid Turnstile token is received and successfully verified server-side. Invalid, expired, or missing tokens are treated as non-legitimate submissions.

</details>

<details>

<summary>How to test that Turnstile is correctly configured?</summary>

A quick validation is to submit the enrolment form from a normal browser session and confirm it completes without friction. A second validation is to open the same flow in a stricter context (private browsing, disabled third-party cookies, VPN, or automation tooling) and confirm Turnstile still behaves as expected.

Cloudflare documents recommended test patterns and integration steps in the setup guide: [Turnstile “Get started”](https://developers.cloudflare.com/turnstile/get-started/).

</details>

<details>

<summary>Which domain should be configured on the Cloudflare widget?</summary>

Add the **custom domain** that hosts the enrolment form.

This is configured in the Turnstile widget settings in Cloudflare. Cloudflare’s setup guide covers widget configuration details: [Turnstile “Get started”](https://developers.cloudflare.com/turnstile/get-started/).

</details>


# Redirects

Create managed URLs and QR codes for store-specific enrolment journeys.

Redirects create a short, managed URL for an enrolment form. They add context, such as a store, seller, language, or campaign source, without duplicating the form.

This approach keeps distribution links consistent and makes performance measurable across locations and campaigns.

<details>

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

* A retail Brand prints one QR code per store. Each code adds the correct `storeId`.
* A clienteling team uses a seller code to attribute enrolments to each associate.
* A campaign QR code sets `neo.src` to separate event scans from email traffic.

</details>

### Plan the redirect

Define the enrolment form and the context carried by the link before creating a redirect. A redirect should serve one clear distribution use case.

For each redirect, confirm these details:

* **Destination:** the enrolment form layout that opens.
* **Label:** a clear operational name, such as `Paris-Rivoli-summer-2026`.
* **Parameters:** the context added when the link is opened.

Use `storeId` when the journey must identify a store. The value must match the identifier in [Stores](/guides-enrolment/enrolment/enrolment-form/stores).

Common supporting parameters are:

* `associateId` for seller attribution.
* `neo.lg` for the display language.
* `neo.src` for the distribution source.

### Create a redirect

Create redirects manually when the distribution context is unique or requires review before publishing.

{% stepper %}
{% step %}

#### Open Redirects

In the administration console, open **Forms → Redirects**. Select **Add New**.

<figure><img src="/files/LdjmuM92vjDzBNOzFsvT" alt="The Wallet Crew administration console navigation"><figcaption><p>Open the Redirects section from the Forms menu.</p></figcaption></figure>
{% endstep %}

{% step %}

#### Select the destination

In **Layout**, select the enrolment form layout that should open. In **Label**, enter a name that identifies the location or campaign.
{% endstep %}

{% step %}

#### Add the context

Select **Add Parameter** and add the required key and value. For store routing, use `storeId` and the matching store-data identifier.

Add `associatId`, `neo.lg`, or `neo.src` only when the journey needs seller attribution, a language override, or source tracking.
{% endstep %}

{% step %}

#### Save and verify

Save the redirect. Open its generated link once and confirm that the expected form and context load.
{% endstep %}
{% endstepper %}

### Import redirects in bulk

Bulk import supports large store networks and repeated campaign patterns. It reduces manual work and keeps redirect naming consistent.

Prepare an Excel file with these columns:

* `Layout`
* `Label`
* `StoreId`

Return to **Forms → Redirects** and import the file. Review a sample of imported redirects before distributing their QR codes.

### Validate and distribute

Validation prevents incorrect store attribution and broken enrolment journeys. Test each redirect with a known form configuration before printing or publishing it.

#### Preview the QR code

Select the three-dot menu beside a redirect, then select **View**. Confirm that the preview includes the correct parameters and opens the intended form.

#### Download QR codes

Select **Download** to export QR codes as a ZIP file. The export contains `.png` and `.svg` versions for digital and print use.

#### Monitor redirect activity

Select **View statistics** from the three-dot menu. Choose a date range to review scan volume, compare stores, and assess campaign performance.

#### Delete a redirect

Delete a redirect when its enrolment journey, store, or campaign is no longer active, for example when a physical store closes.

{% stepper %}
{% step %}
**Open Redirects**

In the administration console, open **Forms → Redirects**.
{% endstep %}

{% step %}
**Delete the redirect**

Select the three-dot menu beside the redirect, then select **Delete**. Confirm the deletion.
{% endstep %}
{% endstepper %}

{% hint style="info" %}
Deleting a redirect invalidates its generated QR code and link. Update or remove any printed or distributed QR codes pointing to a deleted redirect to avoid broken enrolment journeys.
{% endhint %}

### FAQ

<details>

<summary><strong>When should a redirect be used?</strong></summary>

Use a redirect when an enrolment form needs distribution-specific context. Store QR codes, seller links, language-specific links, and tracked campaign links are common uses.

</details>

<details>

<summary><strong>Can several redirects use the same enrolment form?</strong></summary>

Yes. Each redirect can open the same form while adding different parameters. This supports one shared form across several stores or campaigns.

</details>

<details>

<summary><strong>How should store QR codes be validated?</strong></summary>

Scan a sample of generated QR codes before printing. Confirm that each link opens the correct form and carries the expected `storeId`.

</details>

<details>

<summary><strong>Which QR-code format should be used?</strong></summary>

Use `.svg` for print materials because it scales without quality loss. Use `.png` for digital channels that require a raster image.

</details>

<details>

<summary><strong>Can a redirect be disabled temporarily?</strong></summary>

No. Redirects cannot be disabled. Delete the redirect when it is no longer needed, then update or remove any QR codes and links that point to it.

</details>

<details>

<summary><strong>Can a deleted redirect ID be reused?</strong></summary>

No. Redirect IDs are generated automatically and cannot be selected. Once deleted, a redirect ID cannot be reused.

</details>


# Stores

Create and import store location data for enrolment journeys and wallet pass experiences.

Store data creates a shared reference for each physical location. It gives each store a unique identifier and location details that can be used in enrolment journeys, redirects, and wallet pass configurations.

Use store data when one programme operates across several locations. It keeps location context consistent and avoids manually adding the same store information to every journey.

<details>

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

* A retail Brand adds a `storeId` to each in-store QR code for location-level enrolment reporting.
* An event organiser stores venue details for ticket distribution and customer support.
* A luxury Brand connects a clienteling journey to the store where the customer enrolled.

</details>

### Why store data matters

Store data links a digital wallet journey to a physical location. This supports accurate attribution, localised customer experiences, and reliable operational reporting.

The `storeId` is the key value. It must stay stable because redirects and other configurations use it to identify the location.

### Create a store

Create stores individually when opening a new location or maintaining a small store network.

{% stepper %}
{% step %}

#### Open store data

In the administration console, open **Integration → Data → Store**.

<figure><img src="/files/N7Q1VQ2c5q0k6RSrTLwj" alt="Store data section in The Wallet Crew administration console"><figcaption><p>Open the Store section to manage location data.</p></figcaption></figure>
{% endstep %}

{% step %}

#### Add a store

Select **Add New** to open the store-data form.
{% endstep %}

{% step %}

#### Enter the store details

Add the required store information:

* **`storeId`** — a unique, stable identifier for the location.
* **Name** — the store or venue name.
* **Address** — the location address.

<figure><img src="/files/JBdnXNqpYxC7BcI7JQEf" alt="Store data form with fields for store ID, name, and address"><figcaption><p>Use a unique store ID and recognizable location details.</p></figcaption></figure>
{% endstep %}

{% step %}

#### Save and verify

Select **Save**, then confirm that the new store appears in the store list.

<figure><img src="/files/keHgiR0Jwusz82GUR0dy" alt="Saved store data record in The Wallet Crew administration console"><figcaption><p>Verify the saved record before using its store ID in a redirect.</p></figcaption></figure>
{% endstep %}
{% endstepper %}

### Import several stores

Use an Excel import when adding or updating many locations. Include the same core fields used for manual creation: `storeId`, name, and address.

Additional store-specific data can also be included when needed, such as a ticket code. Keep column names and identifier values consistent across imports.

<figure><img src="/files/sD3NGXtGJUN8BYkaEgQ2" alt="Excel import interface for several store data records"><figcaption><p>Import store data in bulk to maintain a large location network efficiently.</p></figcaption></figure>

### Use store IDs in enrolment journeys

Store IDs connect location data to distribution channels. For example, a [Redirect](/guides-enrolment/enrolment/enrolment-form/redirect) can add `storeId` to an enrolment form URL.

Before publishing a store-specific QR code or link, confirm that its `storeId` matches an existing store record. This prevents missing location context and inaccurate reporting.

### FAQ

<details>

<summary><strong>What makes a good store ID?</strong></summary>

Use a unique and stable value from an existing business system when possible. Avoid values that may change when a store name, address, or local team changes.

</details>

<details>

<summary><strong>Can one enrolment form support several stores?</strong></summary>

Yes. Use the same form with separate redirects. Each redirect can add the relevant `storeId` for its location.

</details>

<details>

<summary><strong>Should stores be created manually or through import?</strong></summary>

Create individual stores manually for one-off changes. Use Excel import for a new store network or repeated updates across several locations.

</details>

<details>

<summary><strong>What should be checked after importing stores?</strong></summary>

Verify a sample of records. Confirm that each store ID is unique and that its name and address match the intended location.

</details>


# Download pages

Configure hosted download pages that let customers save one or more Apple Wallet and Google Wallet passes.

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) when registration, identity checks, or consent collection must happen first.

Use [On your website](/guides-enrolment/enrolment/on-your-website) to embed an Add to Wallet button in an existing web experience. Use [On your mobile app](/guides-enrolment/enrolment/readme-1) 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) — capture data before issuing a pass.
* [On your website](/guides-enrolment/enrolment/on-your-website) — add wallet actions to an existing website.
* [Via Email](/guides-enrolment/enrolment/via-email) — send secure pass links to existing customers.
* [On your mobile app](/guides-enrolment/enrolment/readme-1) — 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) 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>


# On your website

Embed an “Add to Wallet” button on your website with The Wallet Crew cinto SDK (Apple/Google detection + desktop fallback).

**cinto** is The Wallet Crew's JavaScript SDK for embedding Add to Wallet buttons on any web page. Use it to place an **Add to Wallet** button on any website — the SDK detects the device and renders the right call to action automatically.

On iOS, it shows **Add to Apple Wallet**. On Android, it shows **Add to Google Wallet**. On desktop, it can redirect to a hosted pass page or support a QR-based fallback.

<details>

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

* A loyalty account page shows one button for the logged-in customer card.
* A gift card area shows one button per active gift card.
* A ticketing page shows one button per ticket, not one button per order.

</details>

<figure><img src="/files/23FG5DjFJVsDSLtL6JHO" alt="Add to Wallet button embedded on a website with device-specific rendering."><figcaption><p>The same integration adapts the button to iOS, Android, and desktop.</p></figcaption></figure>

## How website embed works

The integration is simple. A page loads the cinto SDK, then renders a button that resolves one pass.

That pass can be resolved in two ways:

* with a known `passId`
* with `externalIdentifiers` and an optional HMAC

### Each pass must be unique

This point is critical. A wallet pass is **not** a shared asset.

Each pass must represent one customer, one card, one ticket, or one entitlement instance. The button shown on a page must resolve the pass that belongs to the current context only.

For example:

* a loyalty card page should resolve the current customer card
* a ticket list should resolve one distinct pass per ticket
* a gift card list should resolve one distinct pass per gift card

{% hint style="warning" %}
Never reuse the same static identifier value for every customer. If the same `customerId`, ticket id, or pass lookup value is hardcoded for all visitors, the same pass can be returned to everyone.
{% endhint %}

When `externalIdentifiers` are used, the identifier value must be unique enough to resolve **exactly one pass**. If a lookup returns several passes, the identifier strategy is not specific enough for website distribution.

### What changes by device

The SDK renders the correct behavior automatically:

* **iOS:** downloads the Apple Wallet pass
* **Android:** opens the Google Wallet save flow
* **Desktop:** redirects to a hosted pass page

This default can be overridden when needed with `platform`.

#### Example rendering

**iOS**

<img src="/files/EiY94FUadB2cUUHR5WOE" alt="Add to Apple Wallet button shown on iPhone." width="250">

**Android**

<img src="/files/S4l7ZJ7GMj1AGFq30DBl" alt="Add to Google Wallet button shown on Android." width="250">

**Desktop**

<img src="/files/AZ8O4teLuwGhPwN3BRZw" alt="Desktop fallback rendering for Add to Wallet." width="250">

The desktop fallback opens a hosted pass page such as:

![Hosted pass page used as desktop fallback for website distribution.](/files/CEt8VQnG1yjCyMcYVKzd)

{% hint style="info" %}
Desktop behavior can be customized to display a QR code instead of a standard button.
{% endhint %}

## Choose how the button resolves the pass

The main implementation choice is the pass resolution method.

Use `passId` when the backend already knows the exact pass. Use `externalIdentifiers` when the website has access to a stable business identifier and the pass must be resolved dynamically.

### Start with `tenantId` and `environment`

Two SDK values are especially important:

* `tenantId`
* `environment`

`tenantId` is required. It is the tenant name in The Wallet Crew system. In the examples on this page, `molia` is the `tenantId`.

`environment` is the public base URL used by the SDK.

Use these values as follows:

* **Production:** `https://<customDomain>` the generic `https://app.neostore.cloud` can also be used when no custom domain has been configured
* **Testing / QA:** `https://app-qa.neostore.cloud`

{% hint style="info" %}
If `environment` is omitted, the SDK uses `https://app.neostore.cloud`. This default is valid for production.
{% endhint %}

### Option 1 — Resolve with `passId`

This is the simplest option. It works best when the backend already knows the exact pass to display.

{% tabs %}
{% tab title="Vanilla JavaScript" %}

```html
<script type="text/javascript">
(function (n, e, o) {
var s=n.createElement("script");s.src="https://sdk.neostore.cloud/scripts/"+e+"/cinto@1";s.async=1;
s.onload=function(){neostore.cinto.initialize(e,o)};n.body.appendChild(s);
})(document, "molia", {});
</script>

<div data-neostore-addToWalletButton data-neostore-passId="KlnqcxVLA9pS4ol5"></div>
```

{% endtab %}

{% tab title="npm module" %}

```bash
npm install @neostore/cinto
```

```jsx
import { AddToWalletButton } from "@neostore/cinto";

const btn = new AddToWalletButton("molia", {
    language: "fr",
    passId: "KlnqcxVLA9pS4ol5",
});

btn.render(document.getElementById("btn"));
```

{% endtab %}
{% endtabs %}

### Option 2 — Resolve with `externalIdentifiers`

This option is useful when the page knows a stable business identifier, such as a loyalty id, a CRM id, or a ticket id, but does not know the `passId` yet.

The identifier must belong to the current customer or object. It must not be a shared constant.

When HMAC is used, the signature should be computed server-side with one of The Wallet Crew secrets.

For example, for a `customerId` of `SC103010` and a secret of `I1M8emrrJSns4Hnuibbm45eWfLQMosPGKSp1JzKsCrXeWmhjE8lZhxC2tfSRX5IJ`, the HMAC value is:

`8c5a9ebdd9b4ac8d2307cc34192f0faed441ef724c043162f0618784173d4d93`

Reference tool: [CyberChef](https://gchq.github.io/CyberChef/#recipe=HMAC\({'option':'UTF8','string':'I1M8emrrJSns4Hnuibbm45eWfLQMosPGKSp1JzKsCrXeWmhjE8lZhxC2tfSRX5IJ'},'SHA256'\)\&input=U0MxMDMwMTA)

{% hint style="warning" %}
The HMAC secret must stay server-side. It must never be exposed in browser code.
{% endhint %}

#### Data attributes

```html
<script type="text/javascript">
(function (n, e, o) {
var s=n.createElement("script");s.src="https://sdk.neostore.cloud/scripts/"+e+"/cinto@1";s.async=1;
s.onload=function(){neostore.cinto.initialize(e,o)};n.body.appendChild(s);
})(document, "molia", { language: "fr" });
</script>

<div data-neostore-addToWalletButton
     data-neostore-passType="user"
     data-neostore-externalIdentifiers-y2.customer_Id-value="SC103010"
     data-neostore-externalIdentifiers-y2.customer_Id-hmac="cbbcfc5xxxxx"
></div>
```

#### Component usage

```jsx
import { AddToWalletButton } from "@neostore/cinto";

const btn = new AddToWalletButton("molia", {
    language: "fr",
    passType: "user",
    externalIdentifiers: {
        "y2.customerId": {
            value: "SC103010",
            hmac: "cbbcfc5xxxxx",
        },
    },
});

btn.render(document.getElementById("btn"));
```

#### Identifier key casing in HTML

Browsers lowercase HTML attribute names. To preserve an uppercase character in an identifier key, prefix the character with `_` in the attribute name.

Example:

* `y2.customer_Id` becomes `y2.customerId`

This rule only affects the HTML attribute name. It does not change the signed value.

## Common behavior and options

### Platform detection

When `data-neostore-addToWalletButton` is used, the component selects the right platform automatically:

* `desktop`
* `apple`
* `google`

To force a platform, set `data-neostore-platform="desktop"` or use the `platform` option in the component.

### Language detection

The SDK uses the browser language by default. If the locale is not available, it falls back to English.

To force a language:

* data attributes: `data-neostore-language="fr"`
* component option: `language: "fr"`

Vanilla Javascript example

```html
<script type="text/javascript">
(function (n, e, o) {
var s=n.createElement("script");s.src="https://sdk.neostore.cloud/scripts/"+e+"/cinto@1";s.async=1;
s.onload=function(){neostore.cinto.initialize(e,o)};n.body.appendChild(s);
})(document, "molia", { language: "fr" });
</script>

<div data-neostore-addToWalletButton data-neostore-passId="KlnqcxVLA9pS4ol5"></div>
```

### Full options

Here is the list of full available options.

```typescript
export interface Options {
    /**
     * Public base URL of the environment.
     * Use "https://app-qa.neostore.cloud" for testing.
     * Use "https://app.neostore.cloud" for production.
     * A tenant custom domain can also be used.
     * @default: "https://app.neostore.cloud"
     */
    environment: string;
    /**
     * Tenant name in The Wallet Crew system.
     * This value is required.
     * Example: "molia"
     */
    tenantId: string;
    /**
     * Name of the pass layout to redirect the user when the user is on desktop
     * @default: undefined // default pass layout of the pass template will be used
     */
    passLayoutName: string;
    /**
     * ISO 639 language code to use to do display the button. When omitted, the language will be automatically detected based on the browser settings.
     * If the value doesn't match any available option, the browser settings will be used otherwise english will be used.
     * @default: undefined
     */
    language?: string;
    /**
     * Identifier of the pass to display or promise of it
     */
    passId: string;
    /**
     * Platform to use to display the button. When omitted, the platform will be automatically detected based on the user agent.
     * Possible values are: "apple", "google" or "desktop"
     *
     * @default: undefined
     **/
    platform?: Platform;
    /**
     * External identifiers to use to aquire the passId
     */
    externalIdentifiers?: Record<string, { value: string; hmac?: string }>;
    /**
     * Pass type to use to aquire the passId
     * Required when externalIdentifiers is set
     */
    passType?: string;
    
    /**
     * Source used for analytics purpose
     */
    source?: {
        /**
         * list of tags to associate to this download. utm_source and utm_campaign will automatically be aggregated to this list
         */
        tags?: Array<string>;
        /**
         * medium to associate to this download. utm_medium will be used if no value is specified
         */
        medium?: string;
        /**
         * origin to associate to this download. the current url (without query) will be used if no value is specified
         */
        origin?: string;
    };

    /**
     * Callback called when the button is clicked
     */
    onClick?: (e: MouseEvent, data: { options: Partial<Options>; platform: Platform }) => void;

    /**
     * Callback when an error occurs
     *
     */
    onError?: (error: string) => void;
}

```

### Styling

The rendered structure is:

* a container provided by the website
  * a link with selector `.neostore-link`
    * an image with selectors `.neostore-img` and `.neostore-link-{{ platform }}`

On desktop, the button can be fully customized. The key output is the hosted pass URL, so the default button can be replaced with a custom CTA or a QR code flow.

On mobile, the button should follow Apple and Google design guidelines. The branded asset, label, spacing, and overall presentation should stay compliant with each provider requirements.

Apple and Google button assets follow each provider guideline:

* [Apple guideline](https://developer.apple.com/wallet/add-to-apple-wallet-guidelines/)
* [Google guideline](https://developers.google.com/wallet/generic/resources/brand-guidelines)

## Desktop customization

On desktop, the most important output is the hosted pass URL. That URL can be used to render a QR code instead of the default redirect button.

```html
<script src="https://cdn.rawgit.com/davidshimjs/qrcodejs/gh-pages/qrcode.min.js"></script>

<div id="qrcode"></div>
<script type="module">
    import { AddToWalletButton } from "https://sdk.neostore.cloud/scripts/molia/cinto@1/cinto.mjs";

    const button = new AddToWalletButton("molia", {
        passId: "KlnqcxVLA9pS4ol5"
    });

    const url = await button.getPassPageUrl();
    new QRCode(document.getElementById("qrcode"), url);
</script>
```

## Add analytics information

The button can send three source values that will be visible in the `Pass:Installed` event, the dashboard, and the Insights API.

* `tags`: list of source tags. `utm_source` and `utm_campaign` are added automatically.
* `medium`: channel label such as `ecomm` or `account`.
* `origin`: source page URL. By default, the current page URL is used without query parameters.

All values are optional.

```html
<div data-neostore-addToWalletButton
     data-neostore-src-tags="tag1,tag2"
     data-neostore-src-medium="ecomm"
     data-neostore-src-origin="originA"
></div>
```

## Retrieve `passId` when the pass already exists

When the pass already exists, the website backend can look it up first, then render the button with the returned `passId`.

{% stepper %}
{% step %}

### Create an API key

Create an API key in the admin console with `tenant.pass:read`.

See:[ API Key](https://docs.thewalletcrew.io/api-reference/)
{% endstep %}

{% step %}

### Query the passes endpoint

Use the configured identifier key to search the pass.

Example:

```bash
curl --globoff -X GET \
  'https://app.neostore.cloud/api/<tenantId>/passes?pageIndex=0&pageSize=10&filter[0].field=identifiers.y2.customerId&filter[0].operator=equals&filter[0].value=04101234' \
  -H 'accept: application/json' \
  -H 'X-API-KEY: <apiKey>'
```

Expected result:

```json
[
  {
    "id": "KlnqcxVLAxxxxxx",
    "passType": "user",
    "identifiers": {
      "y2.customerId": "04101234"
    }
  }
]
```

{% endstep %}

{% step %}

### Validate uniqueness

The lookup should return one pass only.

If zero passes are returned, the pass does not exist yet. If several passes are returned, the identifier is not unique enough for website distribution.
{% endstep %}

{% step %}

### Render the button with `passId`

Once the `id` is known, use it as the `passId` in the website button.
{% endstep %}
{% endstepper %}

## Third-party integration example

<details>

<summary><strong>React wrapper example</strong></summary>

```tsx
import { AddToWalletButton } from "@neostore/cinto";

const CintoMobileAddToWallet = React.forwardRef<
    HTMLButtonElement,
    BoxProps & {
        passId?: string;
    }
>(({ passId, ...props }, buttonRef) => {
    const localRef = useRef<HTMLButtonElement>(null);
    buttonRef = buttonRef || localRef;

    const ctaRef = useRef<HTMLDivElement>(null);
    const cintoButtonRef = useRef<AddToWalletButton>();

    useEffect(() => {
        cintoButtonRef.current = passId
            ? new AddToWalletButton(tenantId, {
                  passId,
              })
            : undefined;
        ctaRef.current && cintoButtonRef.current?.render(ctaRef.current);
        if (passId && cintoButtonRef.current) {
            cintoButtonRef.current?.perform();
        }
    }, [passId, tenantId]);

    return (
        <Box {...props}>
            <div ref={ctaRef} />
        </Box>
    );
});

export default CintoMobileAddToWallet;
```

</details>

## FAQ

<details>

<summary><strong>Should the same button be reused for all customers?</strong></summary>

No. The visual component can be reused, but the resolved pass must change with the current customer, ticket, or gift card context.

</details>

<details>

<summary><strong>Should `passId` or `externalIdentifiers` be used?</strong></summary>

Use `passId` when the backend already knows the exact pass. Use `externalIdentifiers` when the page has a stable identifier and the pass must be resolved dynamically.

</details>

<details>

<summary><strong>Can several buttons be rendered on the same page?</strong></summary>

Yes. This is common for ticket lists and gift card lists. Load the SDK once, then render one button per pass.

</details>

<details>

<summary><strong>Can desktop show a QR code instead of a standard redirect?</strong></summary>

Yes. The hosted pass URL can be used to render a QR code or another desktop-specific CTA.

</details>

<details>

<summary><strong>When should a native app integration be used instead?</strong></summary>

Use a native integration when the wallet flow starts inside an iOS or Android app. For that pattern, see [On your mobile app](/guides-enrolment/enrolment/readme-1).

</details>


# Via Email

Send The Wallet Crew link via email to enroll customers in mobile wallet

## Send “Add to Wallet” links by email

Email is the simplest way to reach existing customers and get them into Apple Wallet or Google Wallet. It works well for loyalty and membership cards because customers already trust this channel, and you can place the call-to-action in journeys you already run (welcome, purchase confirmation, service emails).

The key is to keep links secure. A wallet link is a bearer action. Anyone who gets the URL can try to open it. Use signed URLs or tokens, and avoid personal data in query parameters.

<details>

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

* A retail Brand sends “Your loyalty card is ready” after newsletter sign-up.
* A ticketing operator sends a “Save your ticket” email right after purchase.
* A luxury Brand sends “Add your client card” after an in-store visit, with consent capture.

</details>

### What you need before you start

You need a [pass template](https://docs.thewalletcrew.io/configuration/wallet/template-configuration/how-to-create-a-template) and an issuance flow, plus a way to identify the customer. In most setups, The Wallet Crew resolves a pass either from an internal `passId` or from an external identifier coming from your CRM.

You also need a sender identity that customers trust, and that mailbox providers accept. Configure this once, including the sending domain setup, then reuse it across all journeys.

{% hint style="info" %}
If you plan to send from your own domain, set up SPF/DKIM and a DMARC policy. This improves deliverability and reduces phishing risk.
{% endhint %}

### Choose the right email flow

There are two common flows. Pick one based on whether the customer already exists in your database.

#### Flow A — Customer exists: direct download

Use this when the customer already has a loyalty account (or any stable identifier) and you want a one-tap install. The email contains a secure URL that opens the Wallet Crew pass page and lets the customer save the pass.

To prevent ID enumeration, do not expose predictable identifiers like a loyalty number without a signature or token. This follows the same principle as signed Add to Wallet links described in [Wallet card security](https://docs.thewalletcrew.io/configuration/wallet/wallet-card-security).

**Example: signed direct-download link (HMAC)**

For customers who already exist in your CRM (and you can safely reference them with an internal identifier), you can send a link that directly resolves to their pass.

Example:

`https://app.neostore.cloud/{tenantId}/pass?id.y2.customerId={customerId}&id.y2.customerId.hmac={hmac256(customerId,tenantSecret)}`

Keep the `tenantSecret` server-side. Anyone who has it can generate valid links.

#### Flow B — Customer does not exist: enrolment first

Use this when your email list is larger than your loyalty base, or when you need missing data or consent before issuing a pass. The link sends the customer to an enrolment form, then The Wallet Crew issues the pass at the end of the form journey.

Start here: [Enrolment form](/guides-enrolment/enrolment/enrolment-form).

{% hint style="warning" %}
Avoid putting PII in the URL (email, first name, last name). Use a token that your backend generates and your form can validate.
{% endhint %}

**Example: customer not in your CRM (pre-fill form)**

If the customer is not in your CRM yet, you can use the enrolment flow to capture missing data and then push it to your CRM. Some Brands choose to pre-fill the form using query parameters from their email campaign tool.

Example (not recommended):

`https://app.neostore.cloud/{tenantId}/mobile?email=cyril@neostore.cloud&firstName=Cyril&lastName=DURAND`

{% hint style="danger" %}
This URL is **not signed**. Anyone can edit the query parameters. Avoid this setup in production.
{% endhint %}

**Recommended: token-based enrolment link (no PII in the URL)**

Use a token to secure the link. This avoids exposing personal data in the URL and reduces tampering risk.

In practice, you generate a token from The Wallet Crew (API or back-office), store it in your emailing audience, then inject it into the CTA URL.

Example:

`https://app.neostore.cloud/{tenantId}/mobile?neo.authToken={neostore-JWT}`

**How to include The Wallet Crew links in your emailing tool**

You can use one of The Wallet Crew’s partner connectors (for example Actito or Klaviyo) or your own platform (Mailchimp, Salesforce Marketing Cloud, Brevo/Sendinblue, etc.).

{% stepper %}
{% step %}

#### Generate the token

Generate the token with The Wallet Crew API, or generate it manually from The Wallet Crew back-office.

Use a stable input (typically a customer ID or an email), then keep the token opaque in your campaign tool.
{% endstep %}

{% step %}

#### Store the token in your audience

Store the token in your emailing database as a custom attribute, so you can merge it into the CTA URL.
{% endstep %}

{% step %}

#### Build the CTA URL

Use a button like “Add to Wallet” and point it to a tokenized URL:

`https://app.neostore.cloud/{tenantId}/mobile?neo.authToken={{profile.neostoreJwt}}`

Replace `{{profile.neostoreJwt}}` with your tool’s merge tag syntax.
{% endstep %}
{% endstepper %}

### Add the CTA to your emails

In practice, you embed a link behind a button such as “Add to Wallet”. You can do this in your marketing tool (campaign templates) or in transactional emails sent by The Wallet Crew.

#### CTA examples

![Email CTA example: “Add to Wallet” button inside a branded email](/files/4eTnDxjpJ9MeG2bo9YFb)

*Use a high-contrast button and keep it above the fold on mobile.*

![Email CTA example: “Add to Wallet” link presented as a secondary action](/files/5bM8La9qNynnnRvq8fTf)

*If you have multiple CTAs, keep the wallet CTA visually distinct.*

### Keep links secure (recommended rules)

Signed links and tokens prevent tampering and reduce pass enumeration risk. They also keep personal data out of URLs that can be logged by proxies, mailbox scanners, or analytics tools.

Use these rules:

* Prefer an **opaque identifier** (`passId`) when you can.
* When you must use an **external identifier**, protect it with **HMAC**, a **shared secret token**, or a **JWT**.
* Keep token lifetimes short for email campaigns. Treat the link as a password.
* Assume emails can be forwarded. If forwarding must not work, add an email challenge or another verification step in the journey.

If a deeper security review is needed, cover HMAC, shared secret tokens, and JWT as part of the link design. [Wallet card security](https://docs.thewalletcrew.io/configuration/wallet/wallet-card-security) is the source of truth. For broader organizational controls, see the [Security insurance plan](https://docs.thewalletcrew.io/policies/privacy-and-security/security-insurance-plan).

### Segment your sends and measure adoption

Email works best when you don’t spam customers who already installed the pass. Segment on “pass installed” status when you can, then only target customers who are still not installed.

If install status must be synced back into the CRM, use the available event and integration flows.

You can also tag installs for attribution. If you’re distributing via web pages, see how tagging works with `neo.src` on [On your website](/guides-enrolment/enrolment/on-your-website).

### Supported tools and connectors

You can send emails from your own email platform and embed Wallet Crew links in templates. You can also configure The Wallet Crew to send transactional emails as part of enrolment and verification journeys.

See: [Connectors](/guides-enrolment/enrolment/via-email/connectors).

## FAQ

<details>

<summary><strong>Can we run marketing campaigns with these links?</strong></summary>

Yes. Use your marketing platform to send the campaign, and embed a secure Wallet Crew link behind your CTA.

If The Wallet Crew sends emails for enrolment and verification journeys, configure the sender identity and domain setup first.

</details>

<details>

<summary><strong>Should I include customer email or name in the URL?</strong></summary>

Avoid it. URLs are often logged and scanned. Use a token and let The Wallet Crew (or your backend) resolve the customer server-side.

</details>

<details>

<summary><strong>What happens if a customer forwards the email?</strong></summary>

If the link is a bearer token, the forwarded recipient can try to open it. If you must prevent that, use a short-lived token and add a verification step (email challenge) before issuing or revealing the pass.

</details>

<details>

<summary><strong>How do we avoid emailing customers who already installed the pass?</strong></summary>

Segment your audience on install status, then target only “not installed” profiles. If the data must flow back into the CRM, use the installation status events in the integration setup.

</details>

<details>

<summary><strong>Where should this live: email, website, or mobile app?</strong></summary>

Use email when you already have a customer address and you want a low-effort conversion path.

Use web when the pass is installed from a logged-in area or checkout: [On your website](/guides-enrolment/enrolment/on-your-website).

Use native app when you have an app and you want the fastest UX: [On your mobile app](/guides-enrolment/enrolment/readme-1).

</details>


# Connectors

Connect email providers and marketing platforms to send secure Wallet links.

Use these docs when you want to send emails from your own tools, while still using secure The Wallet Crew links in your templates.

If you want The Wallet Crew to send transactional emails (registration, verification, pass delivery), start with [Email provider](/connectors/email-provider).

### Transactional email connectors (The Wallet Crew sends)

* [SendGrid](/connectors/email-provider/sendgrid)
* [Mailchimp](/connectors/email-provider/mailchimp) (Transactional / Mandrill)
* [Salesforce Marketing Cloud](/connectors/email-provider/salesforce-marketing-cloud)
* [Adobe Marketing Cloud](/connectors/email-provider/adobe-marketing-cloud)

### Marketing tools (you send, you embed links)

These integrations are typically used to orchestrate journeys and personalization. You keep full control of deliverability and campaign performance, and you place The Wallet Crew links behind your CTAs.

* [Actito](/connectors/marketing-automation/actito)
* [Klaviyo](/connectors/marketing-automation/klaviyo)


# On your mobile app

Add “Add to Wallet” in a native app using server-side payloads for Apple and Google Wallet.

Make it easy for users to install Wallet passes directly from within your mobile app. Instead of redirecting users elsewhere, your app stays in control of identity, entitlements, and data while Wallet provides instant access to passes offline, surfaces them at the right time, and updates them live. In-app installation ensures a fast, convenient experience users can present at a store or event without having to reopen your app.

<figure><img src="/files/Dx6KBrHSgJWC3ZchP8Mw" alt="Mobile App Add To Wallet SDK integration"><figcaption></figcaption></figure>

## Add to Wallet from your mobile app

On both Apple Wallet and Google Wallet, the flow is consistent. Your app detects whether the pass is already installed, shows the right “Add to Wallet” button, and launches the system save flow when needed.

{% hint style="info" %}
Your app cannot force installation. The user must always confirm in the system UI.
{% endhint %}

### Native app and Wallet are complementary

A wallet does not replace your native app. They solve different jobs, and they work best together. Wallet focuses on presentation and convenience. It gives quick access, offline usage, and OS-level storage. It can also surface passes at the right moment (lock screen, time, location).

Your app handles accounts, authentication, settings, and the full feature set. The Wallet Crew is where passes are created, refreshed, and revoked.

### Why include “Add to Wallet” in your app

Adding the button reduces friction at real touchpoints. Users install the pass in one tap, then present it without reopening the app. That matters when the line is long and the network is weak.

Wallet also keeps the pass reachable for months, and it can stay reachable even if the app is later uninstalled. On the analytics side, you can measure adoption and placement performance by tagging installs with `neo.src`.

<details>

<summary>Real-world examples</summary>

Here are examples of what a pass can unlock once it’s in Wallet:

* Membership: “Free shipping” on every online order.
* Retail: “10% off all purchases” during the whole season.
* Event ticketing: “Fast lane entry” available for this event.
* Event ticketing: “Seat upgrade” applied automatically when available.
* Service: “Priority support” available for every ticket submission.

</details>

### Typical end-to-end flow

The platform details differ, but the product flow stays the same. The user signs in, taps the button, and your app calls your backend. Your backend fetches the right pass from The Wallet Crew and returns an install payload that matches the device (Apple `.pkpass` or a Google JWT). The app then opens the native wallet save UI, and you track installs through Wallet Crew events.

{% @mermaid/diagram content="sequenceDiagram autonumber actor User participant App as Mobile app participant Backend as Your backend participant TWC as The Wallet Crew backend participant Wallet as Apple/Google Wallet (system UI)

```
User->>App: Tap “Add to Wallet”
App->>Backend: Request install payload (user context + device)

Backend->>TWC: Resolve passId (lookup by external identifier)
TWC-->>Backend: passId

Backend->>TWC: Fetch install payload (passId + device + neo.src)
TWC-->>Backend: Apple .pkpass OR Google JWT

Backend-->>App: Return install payload
App->>Wallet: Launch system save flow
Wallet-->>User: Preview + confirmation
User->>Wallet: Confirm installation

Wallet->>TWC: Register installation (provider callback)
TWC-->>Backend: (Optional) Pass:Installed event (webhook)" %}
```

{% hint style="warning" %}
Never call The Wallet Crew APIs from the mobile client with an API key. Keep secrets on your backend only.
{% endhint %}

### Apple Wallet vs Google Wallet

Your mobile app uses native wallet UI, but it never talks directly to The Wallet Crew with an API key. Your backend is the only component that calls **The Wallet Crew backend** to resolve `passId` and generate the install payload.

{% tabs %}
{% tab title="Apple Wallet (iOS)" %}
Apple Wallet uses a **signed pass bundle**.

Your backend requests an Apple install payload from The Wallet Crew backend. It returns a downloadable `.pkpass`.

Your iOS app downloads the `.pkpass` and presents it with PassKit. iOS shows the standard preview sheet, and the user confirms installation. The pass is then stored locally on the device.

Use the “Add to Apple Wallet” label.
{% endtab %}

{% tab title="Google Wallet (Android)" %}
Google Wallet uses **cloud-linked objects**.

Your backend requests a Google install payload from The Wallet Crew backend. It returns a Save payload, commonly a JWT, for the Google Wallet save flow.

Your Android app launches the Google save UI. The user confirms installation. The pass is linked to the user’s Google account, and it can sync across devices.

Use the “Add to Google Wallet” label.
{% endtab %}
{% endtabs %}

## How to implement it

Your tenant must be ready for Apple Wallet and/or Google Wallet, and you must already have a [template](https://docs.thewalletcrew.io/configuration/wallet/template-configuration/how-to-create-a-template) and issuance flow. You also need a backend that your app can call, because secrets and pass lookup must stay server-side.

#### High-level architecture

At a high level, your backend resolves a stable identifier into a `passId`, then calls The Wallet Crew APIs using `X-API-KEY`. Your app only receives the provider-specific install payload and installs the pass using native wallet APIs.

#### Step-by-step

{% stepper %}
{% step %}

### Create an API key (backend only)

Create an API key in the admin console.\
Use least privilege.\
Keep it on the backend only.

You will send it as:

`X-API-KEY: <your_api_key>`
{% endstep %}

{% step %}

### Resolve the passId on your backend

Use your own stable identifier.\
Examples: loyalty ID, customer ID, ticket ID.

Call the passes list endpoint with a filter.

Example (lookup by `identifiers.ur.customerId`):

```bash
curl --globoff -X GET \
  'https://app.neostore.cloud/api/<tenantId>/passes?pageIndex=0&pageSize=10&filter[0].field=identifiers.ur.customerId&filter[0].operator=equals&filter[0].value=<customerId>' \
  -H 'accept: application/json' \
  -H 'X-API-KEY: <your_api_key>'
```

Adapt `filter[0].field` to your own identifier key.\
Typical keys look like `identifiers.<namespace>.<name>`.

You’ll get a JSON array containing the pass `id`.\
That `id` is the `passId` you’ll use next.
{% endstep %}

{% step %}

### Generate a provider-specific “install payload”

Once you have `passId`, request the payload for the target device. Apple returns a downloadable `.pkpass` file, and Google returns a JWT token. A typical endpoint pattern looks like this:

`GET https://app.neostore.cloud/api/<tenantId>/passes/<passId>?device=<apple|google>&neo.src=<tracking>`

{% hint style="info" %}
`neo.src` is used for tracking and attribution.\
Format: `<medium>|<tag1>,<tag2>|<originUrl>`.
{% endhint %}
{% endstep %}

{% step %}

### Install the pass from the app

Use native wallet SDKs. On iOS, download the `.pkpass` and present the “Add to Apple Wallet” UI. On Android, pass the JWT to the Google Wallet save flow.

Provider docs:

{% embed url="<https://developer.apple.com/documentation/passkit/pkaddpassbutton/>" %}

{% embed url="<https://developers.google.com/wallet/retail/loyalty-cards/android>" %}
{% endstep %}

{% step %}

### Track installs and handle re-installs

Use Wallet Crew events to measure adoption and sources. In practice, you tag each in-app placement with `neo.src` (profile, checkout, onboarding) and subscribe to `Pass:Installed` events (webhook) or query adoption via Insights.
{% endstep %}
{% endstepper %}

## FAQ

<details>

<summary>Can I put the API key in the mobile app?</summary>

No. Treat API keys like passwords. Put API calls behind your backend.

</details>

<details>

<summary>Can the app call the “install payload” endpoint directly?</summary>

Yes, if you only use a `passId` and you **do not** use an API key. This is typically safe because `passId` is opaque and non-guessable.

Do **not** implement pass lookup (by customer ID) on the client.

</details>

<details>

<summary>Should I use native wallet flows or the website SDK in a mobile app?</summary>

In a mobile app, prefer **native wallet flows**. They give the best UX and the least friction. They also avoid web redirects.

Use the **website SDK** when you distribute from web pages, or when you need a desktop QR fallback.

See: [On your website](/guides-enrolment/enrolment/on-your-website)

</details>

<details>

<summary>How should I integrate “Add to Wallet” in a Flutter app?</summary>

This pattern works well in Flutter. Keep pass lookup and payload generation on your backend, then trigger the native iOS/Android wallet save flows from Flutter.

</details>

<details>

<summary>How should I integrate “Add to Wallet” in a React Native app?</summary>

Use native modules or a maintained wallet library, then launch the native save flow on each platform. A practical starting point is: <https://habr.com/en/articles/858858/>

</details>

<details>

<summary>Apple vs Google: what do I receive?</summary>

Apple Wallet returns a `.pkpass` file. Google Wallet returns a JWT. Your backend should pick the right payload per device.

</details>

<details>

<summary>What if the pass does not exist yet?</summary>

Create it first, then re-run the same flow to fetch the `passId` and install payload.

</details>


# Engage and Animation Guides

A pass that just sits in a wallet is a missed opportunity. The Engage & animate tools turn every pass into an active touchpoint — rewarding loyalty, surfacing timely offers, and reaching customers exa

## Animation & engagement : step by step

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-cover data-type="files"></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4><i class="fa-location-crosshairs" style="color:$primary;">:location-crosshairs:</i></h4></td><td><h3>Geolocated notifications</h3></td><td><p>Show a contextual message near a location when a customer is nearby for reminders, on-site information, or store/venue alerts.</p><p><br></p></td><td><a href="/files/EmqbDCcJJtGAjsGz9iBG">/files/EmqbDCcJJtGAjsGz9iBG</a></td><td><a href="/pages/uf6YrsT1flt6Zp32jhz7">/pages/uf6YrsT1flt6Zp32jhz7</a></td></tr><tr><td><h4><i class="fa-arrows-from-line" style="color:$primary;">:arrows-from-line:</i></h4></td><td><h3>Privilege &#x26; animation</h3></td><td>Manage how customer benefits, rewards, and pass privileges are activated and surfaced in Apple Wallet and Google Wallet.</td><td><a href="/files/Pu3wyos0qU4LEyWTHqW8">/files/Pu3wyos0qU4LEyWTHqW8</a></td><td><a href="/pages/o3rtIjC8qzwTa0iXxgmB">/pages/o3rtIjC8qzwTa0iXxgmB</a></td></tr><tr><td><h4><i class="fa-exclamation" style="color:$primary;">:exclamation:</i></h4></td><td><h3>Push notifications</h3></td><td>Compare Apple Wallet and Google Wallet push notifications: triggers, limits, and common use cases with The Wallet Crew.</td><td><a href="/files/LXuVJ7V90sFczzyhawfX">/files/LXuVJ7V90sFczzyhawfX</a></td><td><a href="/pages/qNx8x7yAchOPmJVNxyyk">/pages/qNx8x7yAchOPmJVNxyyk</a></td></tr></tbody></table>

**Privileges and activations let you turn a static pass into a living engagement tool.** A privilege is a benefit attached to an individual pass — a discount, a free item, an unlockable reward, a stamp counter — that can be added, updated, or removed at any time without reissuing the pass. Four behavior types cover virtually every loyalty or campaign scenario: OneTime (redeem once), Unlimited (always available while valid), MultiUse (a limited number of uses), and Unlockable (revealed once a condition or progress threshold is met). Each pass can carry up to five privileges at once, with priority rules resolving any conflicts automatically.

**Privileges can come from anywhere in your stack.** They're generated internally by activations, pushed externally through marketing connectors like Salesforce Marketing Cloud or Bloomreach, or created and updated directly via the API. Every privilege carries its own appearance (image, colors), content (title, description), call-to-action links, and a movement-based value history — making it easy to track balances, progress, or redemption codes over time. From event tickets with unlockable afterparty access, to loyalty cards with tiered discounts, gift cards with redeemable balances, and membership passes with monthly quotas, privileges adapt to any real-world use case while keeping the core pass untouched.

**Push notifications complete the engagement loop**, with native, real-time delivery on both Apple Wallet and Google Wallet. Apple notifications are tied to pass updates and appear directly on the lock screen with full message content; Google Wallet offers more flexible, on-demand messaging — including clickable links and rich "Value-Added" content blocks — within a 3-per-day limit. Notifications can be triggered by geolocation, scheduled dates, or events from connected systems (CRM, POS, ticketing), giving brands a single, unified way to keep customers informed and engaged directly from their wallet.


# Geolocated Notifications

Surface a pass message when a customer is near a configured location (store or venue).

Geolocated notifications show a contextual message near a location. Apple Wallet or Google Wallet can surface it when a customer is nearby. Use it for reminders (“don’t forget your card”) and on-site information (“gate changed”).

<figure><img src="/files/sJ7a4To7kdSK0y6dOFkA" alt=""><figcaption></figcaption></figure>

This works for **stores and any venue**. Typical venue examples are stadiums, concert halls, theaters, and pop-ups.

<details>

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

* Remind loyalty members to scan their card at checkout.
* Display a voucher reminder only if a voucher is available.
* Announce a store opening to customers near that location.
* Remind ticket holders of gate/door info when approaching the venue.
* Surface a “your ticket is ready” message near the venue entrance.

</details>

{% hint style="info" %}
Geolocated notifications appear only if the customer enables location features for their wallet app.

On iOS: **Settings → Privacy & Security → Location Services → Wallet**.

On Android: check Google Wallet permissions in your device **Settings** (location must be allowed).
{% endhint %}

## How it works

Wallet passes can store a small set of “relevance” locations. The phone compares the device position to those locations. When the customer enters the configured radius, the wallet app can surface the pass and its message.

The Wallet Crew configures these locations on the pass based on your location dataset. Most brands use store addresses. For venues, you usually model the venue as a “store” record so it can be geolocated the same way.

### What customers will see (varies by platform)

{% tabs %}
{% tab title="Apple Wallet (iOS)" %}
iOS can surface a lock screen suggestion when the customer is near one of the configured locations. The suggestion can include the message you configured.
{% endtab %}

{% tab title="Google Wallet (Android)" %}
Android can surface a “nearby pass” experience when the customer is near one of the configured locations. The exact UI depends on Android version and device manufacturer.
{% endtab %}
{% endtabs %}

### Limits you should design for

These platform limits apply:

* Up to **10 GPS coordinates** per pass.
* Up to **300 m radius** per coordinate.

Message visibility is controlled by the OS. In practice, the message can remain visible while the customer stays in the area.

### Geolocation vs “push notifications”

Geolocated notifications are not “sent” at a specific time by The Wallet Crew. They are triggered by the customer’s phone when it detects proximity.

If you need a server-triggered message, use standard wallet notifications instead. Start with [Push notifications](/guides-animation/engage-and-animate/automatisation/push-notifications).

## Prerequisites

You must configure locations (addresses) in The Wallet Crew. The platform uses those addresses to compute GPS coordinates.

Locations are managed through the **Stores** dataset. You can use it for retail stores and for venues. Example: create a store entry for `Stadium - Gate A` or `Concert hall - Main entrance`.

If you have not set up locations yet, start with [Stores](https://docs.thewalletcrew.io/guides-enrolment).

<div data-with-frame="true"><figure><img src="/files/oCDaFlExS08CicFQqdJs" alt="The Wallet Crew back office showing store and address configuration"><figcaption><p>Addresses are used to compute GPS coordinates (stores or venues).</p></figcaption></figure></div>

## Set up the message in The Wallet Crew

Configure the message directly on the pass template. Use Liquid if you need personalization.

{% stepper %}
{% step %}

#### Open the notification settings on a template

Go to **Templates**. Open the template **More options** menu, then select **Notifications**.
{% endstep %}

{% step %}

#### Write the message (Geo notification tab)

Open the **Geo notification** tab. Write your message. Add Liquid variables if needed.

Keep it short. Aim for **≤ 140 characters** to avoid truncation.
{% endstep %}

{% step %}

#### Configure translations (optional)

If your template is translated, update the geo notification message for each language.
{% endstep %}

{% step %}

#### Save and test

Click **Send notification** to save. Then test with a device near a configured location.

Validate both the location behavior and the Liquid rendering.
{% endstep %}
{% endstepper %}

<div data-with-frame="true"><figure><img src="/files/8zDtSkUARA1od9DVb9n2" alt="Notification configuration screen showing the Geo notification tab"><figcaption><p>Geo notification messages are configured per template and can be translated.</p></figcaption></figure></div>

## How The Wallet Crew selects locations per customer

The location selection logic depends on your use case. Loyalty programs typically rely on “home store” logic. Event tickets typically rely on the venue location you assign to the pass.

For a retail-style setup, geolocated notifications are commonly computed for:

* The customer’s **home store**.
* The **9 closest locations** to that home store (or to the customer address).

This keeps the pass within the 10-location limit while covering nearby locations.

## Automatic updates of location coordinates

When you perform a pass update via The Wallet Crew, location coordinates can be recalculated:

* If the customer’s home store changes, the “closest locations” list is recalculated.
* If the customer address changes, the “closest locations” list is recalculated.
* If you add new stores (with an address), they can become eligible as “closest locations”.

This keeps location triggers aligned with your latest location data.

## Liquid examples for geo notification messages

Use Liquid to show a message only to relevant customers. Typical inputs are store identifiers, customer profile data, and voucher availability.

{% code title="Example 1 — show a voucher reminder only if a voucher exists" %}

```liquid
{%- if y2.bons.loyaltyCertificates.size > 0 -%}
Your €20 loyalty voucher is available. Use it in store today.
{%- else -%}
Don’t forget to scan your loyalty card at checkout.
{%- endif -%}
```

{% endcode %}

{% code title="Example 2 — store-specific message" %}

```liquid
{%- if storeId == "013" -%}
This store is permanently closed. Visit our other nearby stores.
{%- else -%}
Welcome back. Your store is nearby. Come discover our latest arrivals.
{%- endif -%}
```

{% endcode %}

## FAQ

<details>

<summary><strong>Can we track how many customers received the geolocated message?</strong></summary>

No. This is not a message that The Wallet Crew actively sends at a given time. The customer’s phone triggers it locally when it gets near the configured coordinates.

</details>

<details>

<summary><strong>Do we know if the customer is inside the store or venue?</strong></summary>

No. Geolocation triggers do not send “entered” or “in-store” events back to The Wallet Crew.

</details>

<details>

<summary><strong>Why didn’t the geo notification show up on an iPhone?</strong></summary>

Start with iOS settings. The customer must enable location access for Wallet in **Settings → Privacy & Security → Location Services → Wallet**.

Then validate the pass data. The pass must include location coordinates. The customer must be close enough to the configured radius.

</details>

<details>

<summary><strong>Why didn’t the geo notification show up on Android (Google Wallet)?</strong></summary>

Start with Android settings. The user must allow location features for Google Wallet (and not restrict it via system privacy settings).

Then validate the pass data. The pass must include locations, and the customer must be close enough to trigger them.

</details>

<details>

<summary><strong>What is the delay between two geolocated notifications?</strong></summary>

The OS typically surfaces the message when the customer enters the configured area. It can disappear when they leave. It can reappear the next time they enter.

Apple’s reference: [Showing a pass on the lock screen](https://developer.apple.com/documentation/walletpasses/showing-a-pass-on-the-lock-screen).

</details>

<details>

<summary><strong>How are the 10 locations selected for one customer?</strong></summary>

Each customer has a home store. The Wallet Crew selects the 9 closest locations to that home store, for a total of 10.

</details>

<details>

<summary><strong>Is this the same as beacon-based notifications?</strong></summary>

No. Beacons use Bluetooth (iBeacon identifiers). Geolocated notifications use GPS coordinates.

Apple Wallet also supports beacon triggers. If you plan to use them, confirm your target devices and store hardware constraints first.

</details>


# Privilege & Activation

Privilege & activation covers how customer-specific benefits are reflected on a pass, and how those benefits move from "available" to "active."

<table data-view="cards"><thead><tr><th></th><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4><i class="fa-gift" style="color:$primary;">:gift:</i></h4></td><td><h3>Privilege</h3></td><td>Define customer benefits on each pass, from discounts to tiers, balances, perks, and redeemable rewards.</td><td><a href="/files/adkPI3KmRcKlseRL5ydj">/files/adkPI3KmRcKlseRL5ydj</a></td><td><a href="/pages/4bApkQ3gFAcacvtGxT7K">/pages/4bApkQ3gFAcacvtGxT7K</a></td></tr><tr><td><h4><i class="fa-bolt" style="color:$primary;">:bolt:</i></h4></td><td><h3>Activation</h3></td><td>Trigger privileges at scale using segments, schedules, or events, then update eligible passes automatically instantly.</td><td><a href="/files/QuvTlY5wmI6zXKqPLU2E">/files/QuvTlY5wmI6zXKqPLU2E</a></td><td><a href="/pages/LXqziHfHXP4KuSPnEDN0">/pages/LXqziHfHXP4KuSPnEDN0</a></td></tr></tbody></table>

**Privilege** focuses on what a pass *displays*: tiers, statuses, discounts, points balances, or special perks tied to a customer's profile. This is the data layer — how privilege information is computed, stored, and surfaced as visible fields on the pass, and how it updates over time as a customer's status changes (e.g. moving from Silver to Gold).

**Activation** focuses on *triggering* those privileges: the mechanism that turns a stored benefit into something the customer can actually use, whether through a manual action, a pass update via the API, or a rule-based condition (purchase threshold, date, event). It likely also covers how activation state is reflected back on the pass (badges, fields, or visual indicators).

Together, these two pages explain the loop: a privilege is defined and stored, then activated and reflected on the pass — closing the gap between backend customer data and what shows up in Apple Wallet or Google Wallet.


# Privilege

Define and manage pass privileges (perks) in The Wallet Crew: types, creation sources, priority rules, and movement-based redemption state.

A **privilege** is a benefit attached to a single digital pass. It defines what the holder can do, claim, or unlock. Privileges are separate from the pass itself. You can add, update, or remove them without re-issuing the pass.

### Why privileges matter

Privileges matter because they transform a simple pass into a powerful tool for engagement and loyalty. A pass alone gives access, but a privilege adds a reason for customers to care, interact, and come back. It’s the difference between a standard ticket and an experience that feels personal, rewarding, and memorable.

They matter for marketing because they create opportunities to delight customers, drive incremental revenue, and encourage behaviors that benefit the brand. By offering extras like discounts, free items, or exclusive perks, privileges make each interaction more valuable and strengthen the relationship between the customer and the brand.

Finally, privileges give flexibility and creativity to campaigns. Brands can craft unique combinations of benefits, target different customer segments, or add limited-time rewards, all without changing the core pass. This makes it easier to innovate, test ideas, and deliver moments that turn ordinary access into meaningful experiences.

### How privileges behave

Privileges have a behavioral type:

* **OneTime**: redeem once, then it’s gone.
* **Unlimited**: always available while valid.
* **MultiUse**: limited number of uses.
* **Unlockable**: appears only after progress or conditions are met.

This maps directly to real perks. Free drink, 10% discount, 5 entries, spend-to-unlock rewards.

### How privileges get onto a pass

Privileges are created in various ways. They can be generated **internally** by the platform through [activations](/guides-animation/engage-and-animate/privilege-and-activation/activation). They can also be created **externally** through connectors like [SFMC](https://docs.thewalletcrew.io/configuration) or [Bloomreach](https://docs.thewalletcrew.io/configuration) or either directly via [API](https://docs.thewalletcrew.io/api-reference).

A pass can carry up to **5 privileges** at the same time. Conflicts use **priority**, then **most recent update** as tie-breaker.

## Privilege Definition

A privilege is a structured object. It groups metadata, appearance, content, links, and value/status.

### General properties

| Property              | Description                                                                                                                   |
| --------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `privilegeId`         | Unique identifier of the privilege. Auto-generated by the system.                                                             |
| `priority`            | Integer used to resolve conflicts when multiple privileges modify the same property. Higher wins. If equal, last update wins. |
| `type`                | One of `OneTime`, `Unlimited`, `MultiUse`, `Unlockable`.                                                                      |
| `tags`                | List of tags used for reporting.                                                                                              |
| `origin.generator`    | *(optional)* Name of the process generating the privilege. Use `internal` for platform activations.                           |
| `origin.activationId` | *(optional)* Identifier of the generating process. Example: internal activation id, or an external `journeyId` (SFMC).        |
| `origin.externalId`   | *(optional)* Unique identifier of this privilege in an external system.                                                       |
| `deletionDate`        | Date when the privilege will be deleted from the system. Once deleted, it no longer affects pass rendering.                   |

{% hint style="info" %}
Keep priorities simple. Use a small range like `0–100`.
{% endhint %}

### Type

The platform supports four privilege types. Each type defines how and when a privilege can be used.

<div data-with-frame="true"><figure><img src="/files/i7fuiKaYMv1DT4o8gjic" alt="4 different type of privileges"><figcaption></figcaption></figure></div>

{% tabs %}
{% tab title="OneTime" %}
A **OneTime** privilege can be used **only once**. Once redeemed, it is consumed and cannot be used again.

{% hint style="success" %}
**Real-world use cases**

* Coffee shop: “Free espresso” voucher, redeem once.
* Event: “VIP lounge entry” for one attendee, 1 scan only.
* Retail: “$15 off your next order” code, usable once.
  {% endhint %}
  {% endtab %}

{% tab title="Unlimited" %}
An **Unlimited** privilege can be used **as many times as needed** while valid. It is never consumed.

{% hint style="success" %}
**Real-world use cases**

* Membership: “Free shipping” on every online order.
* Retail: “10% off all purchases” during the whole season.
* Service: “Priority support” available for every ticket submission.
  {% endhint %}
  {% endtab %}

{% tab title="MultiUse" %}
A **MultiUse** privilege can be used a **limited number of times**. Each use reduces the remaining count until the privilege is consumed.

{% hint style="success" %}
**Real-world use cases**

* Gym: “10 entries” pack, each check-in consumes 1.
* Venue: “3 guest passes”, each guest scan consumes 1.
* Car wash: “5 washes”, each wash consumes 1.
  {% endhint %}
  {% endtab %}

{% tab title="Unlockable" %}
An **Unlockable** privilege becomes available **after progress is completed**. It is locked until the required steps are done.

{% hint style="success" %}
**Real-world use cases**

* Restaurant: “Buy 10 pizzas, get 1 free” (progress unlocks the reward).
* Coffee shop: “Collect 8 stamps, get 1 free” (each purchase increments progress).
* Education: “Complete 3 modules, unlock exam voucher” (progress from LMS events).
  {% endhint %}
  {% endtab %}
  {% endtabs %}

### Appearance

| Property          | Description                                                                                                                     |
| ----------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `mainImage`       | *(optional, localizable)* Main image of the privilege. Use it to explain the benefit visually. Keep it readable at small sizes. |
| `thumbnail`       | *(optional, localizable)* Small image for compact UIs. Use a simple pictogram or logo-style asset.                              |
| `backgroundColor` | *(optional)* Background color override for privilege UI elements (when supported).                                              |
| `foregroundColor` | *(optional)* Foreground/text color override for privilege UI elements (when supported).                                         |

{% hint style="info" %}
Images are automatically resized to match Apple Wallet and Google Wallet constraints. Use a wide image. Recommended size: `1200px × 400px`.
{% endhint %}

{% tabs fullWidth="false" %}
{% tab title="Apple Wallet" %}
Will override the main image of the pass.

If the property contains localized values, the phone language selects the localized version. If no localized version exists, `default` is used.

<div data-with-frame="true"><figure><img src="/files/i4F55962qiBhju8CU4wV" alt="Example of pass privilege appearance for apple wallet"><figcaption></figcaption></figure></div>

{% hint style="info" %}
Poster-style event tickets may map images differently depending on your template. If you need exact slot mapping, check your pass template configuration.
{% endhint %}

{% hint style="warning" %}
`thumbnail` is not available for Apple.
{% endhint %}
{% endtab %}

{% tab title="Google Wallet" %}
Shown as the privilege visual when the pass template supports it.

Google Wallet uses a single, non-localized image. Only the default value of `mainImage` / `thumbnail` is used, regardless of the phone language. Per-language localized images are not supported on Google today because of a Google webhook constraint. If localized images are set for Apple and a default image exists in the same privilege, Google uses the default image.

{% hint style="info" %}
There is no need for a separate privilege per language for Google. Put localized images and a default image in the same privilege. Apple picks the localized image per language, while Google, plus any Apple language without a localized version, falls back to default.
{% endhint %}
{% endtab %}

{% tab title="Pass preview" %}
Displayed as the privilege main image in the preview UI.

The preview UI displays the privilege `mainImage`. When localized values exist, the preview follows the same rule as Apple. It shows the selected language's image and falls back to default when no localized version exists.
{% endtab %}

{% tab title="Crew check" %}
{% hint style="danger" %}
TODO — confirm with product whether Crew check renders the privilege image and, if so, whether it uses the localized value or default.
{% endhint %}
{% endtab %}
{% endtabs %}

{% hint style="warning" %}
A privilege is not device-targeted. Every applied privilege is added to the pass for both Apple and Google. Applying two privileges, for example one “localized” and one “generic,” results in both being shown on every pass, and their descriptions stack on the back. Use a single privilege per campaign, combining localized and default images.
{% endhint %}

### Content

| Property      | Description                                                                                                  |
| ------------- | ------------------------------------------------------------------------------------------------------------ |
| `title`       | *(optional, localizable)* Short label for the privilege. Example: `VIP Lounge Access`, `-10%`, `Free drink`. |
| `description` | *(optional, localizable)* Supporting text for users and operators. Use it for conditions and constraints.    |

{% tabs %}
{% tab title="Apple Wallet" %}
{% hint style="danger" %}
TODO
{% endhint %}
{% endtab %}

{% tab title="Google Wallet" %}
{% hint style="danger" %}
TODO
{% endhint %}
{% endtab %}

{% tab title="Pass preview" %}
{% hint style="danger" %}
TODO
{% endhint %}
{% endtab %}

{% tab title="Crew check" %}
{% hint style="danger" %}
TODO
{% endhint %}
{% endtab %}
{% endtabs %}

### Links

| Property           | Description                                                                                       |
| ------------------ | ------------------------------------------------------------------------------------------------- |
| `legalInformation` | *(optional, localizable)* Terms and conditions related to the privilege. Typically a label + URL. |
| `callToAction`     | *(optional, localizable)* Primary action for the privilege. Typically a label + URL.              |

{% hint style="info" %}
Links are usually modeled as `{ "label": "...", "url": "https://..." }`. Exact rendering depends on the pass template.
{% endhint %}

{% tabs %}
{% tab title="Apple Wallet" %}
Shown as the primary privilege action when supported.
{% endtab %}

{% tab title="Google Wallet" %}
Shown as the primary privilege action when supported.
{% endtab %}

{% tab title="Pass preview" %}
Shown as a primary button.
{% endtab %}

{% tab title="Crew check" %}
Shown as an action button for operators.
{% endtab %}
{% endtabs %}

### Data

Use **data** when the privilege carries a redeemable balance, progress, or a code.

| Property    | Type         | Description                                     |
| ----------- | ------------ | ----------------------------------------------- |
| `value`     | `decimal`    | Computed value. Sum of all `movements[].value`. |
| `movements` | `movement[]` | List of value movements (credits/debits).       |
| `content`   | `string`     | Free-form value. Example: promo code.           |

{% hint style="info" %}
Redemption logic is enforced by the consuming system (POS, scanners, apps). The platform stores movements and computes `movementValue`.
{% endhint %}

#### Movement

| Property     | Type              | Description                                                                              |
| ------------ | ----------------- | ---------------------------------------------------------------------------------------- |
| `movementId` | unique identifier | Generated by the platform.                                                               |
| `date`       | `dateTime`        | Date when this movement happened.                                                        |
| `remarks`    | `string`          | Free-form remark (audit/debug).                                                          |
| `value`      | `decimal`         | Can be negative when the privilege is used. Can be fractional for progress (Unlockable). |

{% hint style="info" %}
Your app should check `movementValue` before redeeming. Avoid concurrent redeems on the same pass/privilege.
{% endhint %}

#### Examples

{% tabs %}
{% tab title="OneTime" %}
**Use cases**

* Concert: “1 free welcome drink” for VIP tickets.
* Retail: “1 free gift wrap” on the next purchase.
* Museum: “1 guided tour entry” for a specific date.

Movement timeline (example: VIP welcome drink):

<table data-full-width="false"><thead><tr><th width="148">date</th><th width="97">value</th><th>remarks</th><th>total</th></tr></thead><tbody><tr><td><code>2025-01-12</code></td><td><code>1</code></td><td>privilege applied</td><td><code>1</code></td></tr><tr><td><code>2025-01-15</code></td><td><code>-1</code></td><td>privilege redeemed</td><td><code>0</code></td></tr><tr><td><code>2025-01-15</code></td><td><code>1</code></td><td>rollback</td><td><code>1</code></td></tr></tbody></table>
{% endtab %}

{% tab title="Unlimited" %}
**Use cases**

* Loyalty tier: “10% discount” every time, while tier is active.
* Airline: “1 free checked bag” on every flight segment.
* Subscription: “Unlimited access” to premium content.

For Unlimited privileges, movements are often omitted because nothing is “consumed”.\
If you still store movements for audit (optional), it can look like this:

<table data-full-width="false"><thead><tr><th width="148">date</th><th width="97">value</th><th>remarks</th><th>total</th></tr></thead><tbody><tr><td><code>2025-01-12</code></td><td><code>-1</code></td><td>privilege used</td><td><code>-1</code></td></tr><tr><td><code>2025-01-15</code></td><td><code>-2</code></td><td>privilege used twice</td><td><code>-3</code></td></tr></tbody></table>
{% endtab %}

{% tab title="MultiUse" %}
**Use cases**

* Gym: “10 entries” prepaid pack.
* Festival: “5 drink tokens” linked to the ticket.
* Parking: “20 exits” pack for a company parking card.

Movement timeline (example: gym 10-entry pack):

<table data-full-width="false"><thead><tr><th width="148">date</th><th width="97">value</th><th>remarks</th><th>total</th></tr></thead><tbody><tr><td><code>2025-01-12</code></td><td><code>10</code></td><td>purchase 10-entry card</td><td><code>10</code></td></tr><tr><td><code>2025-01-15</code></td><td><code>-1</code></td><td>consume 1 entry</td><td><code>9</code></td></tr><tr><td><code>2025-01-17</code></td><td><code>-4</code></td><td>consume 4 entries (with friends)</td><td><code>5</code></td></tr><tr><td><code>2025-01-17</code></td><td><code>1</code></td><td>gifted 1 entry</td><td><code>6</code></td></tr></tbody></table>
{% endtab %}

{% tab title="Unlockable" %}
**Use cases**

* Restaurant: buy 10 pizzas, unlock 1 free pizza.
* Coffee shop: collect 8 stamps, unlock 1 free drink.
* Retail: spend $200 in a month, unlock $20 voucher.

Movement timeline (example: buy 10 pizzas, unlock 1 free):

<table data-full-width="false"><thead><tr><th width="148">date</th><th width="97">value</th><th>remarks</th><th>total</th></tr></thead><tbody><tr><td><code>2025-01-12</code></td><td><code>0.2</code></td><td>buy 2 pizzas</td><td><code>0.2</code></td></tr><tr><td><code>2025-01-15</code></td><td><code>0.5</code></td><td>buy 5 pizzas</td><td><code>0.7</code></td></tr><tr><td><code>2025-01-17</code></td><td><code>0.4</code></td><td>buy 4 pizzas</td><td><code>1.1</code></td></tr><tr><td><code>2025-01-17</code></td><td><code>-1</code></td><td>redeem 1 pizza</td><td><code>0.1</code></td></tr></tbody></table>
{% endtab %}
{% endtabs %}

## Real-world use case

Use privileges when you need **stateful perks** on a pass. Native wallet app will automatically display privilege information. For greater experience, it is also possible to use our [Crew Check](https://docs.thewalletcrew.io/guides-scan) application to scan passes and list and redeem privilege.

### Event ticket

Turn a static ticket into a live campaign surface. Keep one pass for entry, then add perks as the event unfolds. Use **OneTime** for single-claim perks (VIP lounge entry, fast-lane access, welcome drink), **MultiUse** for token packs (drink tokens, cloakroom credits), and **Unlockable** for perks that appear after progress.

Example: everyone enters with the same pass, but an **Unlockable** “Afterparty access” privilege appears after the third scan. A **MultiUse** “5 drink tokens” privilege is added at doors open and decremented at the bar.

### Loyalty card

Run promos and tier benefits without changing the card. Let CRM, CDP, or POS update perks as customers progress.

Use **Unlimited** for always-on entitlements (tier discounts, free shipping, priority support). Use **Unlockable** for spend triggers, **MultiUse** for counters (stamps, entries), and **OneTime** for single-hit rewards (birthday, recovery).

Example: give VIP customers an **Unlimited** “15% off” privilege with higher **priority** than campaign discounts. When the customer spends €200 in a month, your CDP adds an **Unlockable** “€20 voucher” privilege, and the POS redeems it once.

### Gift card

Use privileges when the card needs **redeemable value**, **a code**, or both.

Store a balance as **MultiUse** and decrement it with movements per spend. Store a promo code as **OneTime** and consume it at first use.

Example: start a gift card at `+50`. A €12 purchase adds a `-12` movement and leaves `38`. A holiday promo adds a `+10` top-up movement. If that purchase is refunded, add a `+12` rollback movement instead of editing history.

Redemption is enforced by your POS or checkout. The platform stores state and movements for reporting.

### Membership

Use a pass as a membership surface with changing entitlements.

Use **Unlimited** for ongoing access, **MultiUse** for monthly quotas, **OneTime** for single claims, and **Unlockable** for milestone rewards.

Example: a coworking pass has **Unlimited** “premium access” plus **MultiUse** “5 day passes” that reset monthly. After onboarding is completed, an **Unlockable** “1:1 session” privilege becomes redeemable in the booking flow.

## FAQ

<details>

<summary>How many privileges can a pass have at the same time?</summary>

You can attach up to 5 privileges to a single pass at the same time. If you need more benefits, group them into fewer privileges, or rotate them over time.

</details>

<details>

<summary>What happens when multiple privileges conflict?</summary>

When multiple privileges try to modify the same property, priority decides the winner. If priorities are equal, the most recently updated privilege wins.

</details>

<details>

<summary>Do I need to re-issue the pass when a privilege changes?</summary>

No. Privileges are separate from the pass core data. You can add, update, or remove a privilege without re-issuing the pass.

</details>

<details>

<summary>What happens to privileges when a pass is uninstalled and reinstalled?</summary>

Uninstalling or reinstalling a pass does not modify its privileges. Privileges remain attached to the pass on The Wallet Crew servers.

</details>

<details>

<summary>Where do privileges come from?</summary>

You can create privileges internally using activations, or externally through connectors (for example SFMC or Bloomreach). You can also create and update them directly via the API.

</details>

<details>

<summary>How is redemption state stored for MultiUse and OneTime privileges?</summary>

Use movements to track credits and debits. The platform stores the movement history and computes the current `value`, but your consuming system (POS, scanners, app) enforces the redemption rules.

</details>

<details>

<summary>Can I “undo” a redemption?</summary>

Yes, if your process supports it. Instead of editing history, add a new movement that compensates the previous debit (a rollback credit) so the audit trail stays intact.

</details>

<details>

<summary>What does <code>deletionDate</code> do?</summary>

It schedules when the privilege is deleted from the system. After deletion, it no longer affects pass rendering and should no longer be considered during scans and redemption.

</details>


# Activation

An activation applies a privilege (and optionally a notification) to many passes. Use activations for campaigns and scheduled rollouts.

### What an activation contains

1. **Segmentation**: which passes are targeted.
2. **Trigger**: when the activation runs.
3. **Configuration**: what is applied (privilege + optional notification).

### How it differs from a Privilege

A [Privilege](/guides-animation/engage-and-animate/privilege-and-activation/privilege) is the object stored on a pass. An activation is the “batch mechanism” that creates or updates privileges at scale.

### Execution model (high level)

* When the trigger fires, the platform resolves the segment into pass ids.
* The platform applies the configured privilege to each pass.
* Each updated pass is pushed to Apple/Google via the usual update pipeline.

{% hint style="info" %}
Use an activation when you need repeatable logic. Use the privilege API when you target a single pass.
{% endhint %}


# Automatisation


# Push notifications

Compare Apple Wallet and Google Wallet push notifications: triggers, limits, and common use cases with The Wallet Crew.

Wallet notifications help deliver timely information in a familiar channel. Apple Wallet and Google Wallet do not work the same way, so the trigger strategy matters. *Apple Wallet notifications require a pass update. Google Wallet can notify from a message.*

![Diagram comparing push notifications in Apple Wallet vs Google Wallet](/spaces/97ZAXMtqOjhvBBCfpmcE/files/yYsRIPc3VKVy6hlA4WHq)

<details>

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

* A loyalty member receives a points update after a purchase.
* A gift card balance is refreshed after an in-store redemption.
* A ticket holder is alerted about a gate change or schedule update.

</details>

## How push notifications work

### Apple Wallet

Apple Wallet notifications are triggered only when a pass is updated. A field, QR code, or location can change. Notifications appear on the lock screen or in Notification Center. The last message appears on the back of the pass.

Apple also supports automatic pass presentation based on geolocation, dates, or events.

### Google Wallet

Google Wallet can send notifications without a pass update. The notification alerts the customer that a message was added to the pass.

Google Wallet can show the message in pass details only. It can also display the message and generate a notification.

## Update pass information and trigger alerts

The Wallet Crew manages Apple Wallet and Google Wallet passes through a unified API. Connected CRM, ticketing, and POS systems can update pass data in real time.

Common updates include:

* Remaining gift-card balance.
* Coupon or ticket expiry date.
* Promotional content on a pass.

A pass update synchronizes with Apple Wallet and Google Wallet. Platform rules determine whether it generates a notification.

![Example of a pass update triggering a notification](/spaces/97ZAXMtqOjhvBBCfpmcE/files/IoV6jkzQMoUXRHhWcExA)

## Notification types

### Geolocation-based notifications

Apple Wallet uses GPS coordinates to detect when a customer enters or exits a defined area. Google Wallet relies on location information associated with the Google account. This can surface a pass near a store or venue.

![Example of a location-based notification near a store](/spaces/97ZAXMtqOjhvBBCfpmcE/files/vX11vIMtOqmHhQyFTWWL)

### Date- or calendar-based notifications

Brands can configure reminders around pass validity or an event date.

![Example of a scheduled reminder notification for a pass](/spaces/97ZAXMtqOjhvBBCfpmcE/files/SIZDD1N4JtPOguKuhoeI)

### Event-triggered notifications

The Wallet Crew can react to events from CRM, POS, and ticketing systems. Purchases, point accrual, or cancellations can update a pass and trigger a notification.

![Event-triggered notifications driven by connected systems](/spaces/97ZAXMtqOjhvBBCfpmcE/files/7IkSp5HUSYjmljY2no2n)

### Beacon tags

Beacon tags use Bluetooth to detect nearby devices. This capability is available only with Apple Wallet.

![Bluetooth beacon-based notification example (Apple Wallet)](/spaces/97ZAXMtqOjhvBBCfpmcE/files/uA4KUFCEbr7FpPX4E6WB)

## Limits

### Apple Wallet

Notifications can appear on the iPhone lock screen, in Notification Center, and on Apple Watch when enabled.

As of iOS 18, up to three lines are displayed. Keep messages below 140 characters to reduce truncation. Apple Watch usually shows one or two lines.

### Google Wallet

Google Wallet applies the following restrictions:

* Customers must enable pass notifications.
* Message links must relate to the pass.
* A maximum of three messages can trigger a push notification within 24 hours.
* Google Wallet controls the lock-screen notification.

Google may throttle delivery when it detects spam. More information is available in [Google's considerations when sending messages](https://developers.google.com/wallet/retail/offers/use-cases/trigger-push-notifications#some-considerations-when-sending-messages-with-notifications-to-users).

## Key differences

### Notification triggering

Apple Wallet requires a pass update. Google Wallet can notify from a message, independently of a pass update.

### Notification content

Apple Wallet can display message content on the lock screen. Google Wallet usually alerts customers that a message was added. Customers then open the pass to read it.

![Example showing notification content differences between Apple Wallet and Google Wallet](/spaces/97ZAXMtqOjhvBBCfpmcE/files/AcXkYsBXqoB94n1dAr1d)

### Value-added opportunities

Google Wallet can add a title, description, image, and clickable link inside the pass. Apple Wallet does not support this interaction model.

![Example of Google Wallet value-added opportunities (image + link)](/spaces/97ZAXMtqOjhvBBCfpmcE/files/VWnFpAFduR89U9uWWizt)

## The Wallet Crew unified API

The Wallet Crew centralizes pass updates for both platforms. This creates consistent business logic while respecting each wallet's delivery rules.

![Illustration of using one API to manage Apple Wallet and Google Wallet](/spaces/97ZAXMtqOjhvBBCfpmcE/files/INb3QhWfyLNNN1lpGmeG)

## FAQ

<details>

<summary><strong>Can notification text be customized on Google Wallet?</strong></summary>

Not in the same way as Apple Wallet. Google Wallet usually alerts customers that a message was added. They then open the pass to read the content.

</details>

<details>

<summary><strong>Why did a customer not receive a wallet notification?</strong></summary>

Check device settings first. Notifications may be disabled globally or for a specific pass. Then validate the platform trigger.

</details>

<details>

<summary><strong>What are the Google Wallet sending limits?</strong></summary>

Google Wallet limits push-triggering messages to three per 24-hour period for each pass.

</details>

<details>

<summary><strong>Should wallet notifications be treated as marketing?</strong></summary>

It depends on the message purpose. Service messages are usually transactional. Promotions are marketing. See [Consents & GDPR compliance](/guides-animation/engage-and-animate/automatisation/push-notifications/consents-and-gdpr-compliance).

</details>


# How to Send Push Notifications to Apple and Google Wallet

Create and schedule Apple Wallet and Google Wallet push notifications, target pass holders, configure messages, and verify delivery.

## Send push notifications to Apple Wallet and Google Wallet

The Wallet Crew sends wallet notifications to Apple Wallet and Google Wallet pass holders. Use an automation to send a message immediately, on a schedule, after an event, or relative to a pass date.

Apple Wallet displays the configured message on the lock screen. Google Wallet controls the lock-screen notification text. It generally tells customers that a new pass message is available.

<details>

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

* A ticketing platform sends gate details one hour before an event.
* A retailer reminds loyalty members that an offer expires tomorrow.
* A gift-card program confirms a balance update after redemption.

</details>

## Create a push notification automation

This automation combines timing, audience, message, and delivery speed. Configure each setting before saving the notification.

### Open the notification workflow

Open **Engagement** and select **Add a new one** in the top-right corner.

Select **Send a notification**, then select **Next**.

<figure><img src="/files/0iHowe4e4HnKGuD8PwN3" alt="Engagement page showing the Add a new one button"><figcaption><p>Start a new automation from the Engagement section.</p></figcaption></figure>

<figure><img src="/files/vRHM4iS0i5bu8Fy7ce7p" alt="Automation type selector with Send a notification selected"><figcaption><p>Select Send a notification to create a wallet notification automation.</p></figcaption></figure>

### Set the delivery time

Name the notification and choose its delivery time. The name identifies the automation internally.

Choose one of the following delivery options:

* **Now** sends the notification immediately after configuration is complete.
* **Scheduled** sends the notification on a selected date and time.
* **Recurrence** repeats delivery daily, weekly, or monthly.
* **Date relative** uses a **DateTime** metadata field. Set an offset before or after that date.
* **Event** runs after a selected event occurrence. Run it per pass or only after first installation. A delay can be added.

<figure><img src="/files/YP3PdeYpRIemLjLI6Wok" alt="Notification delivery-time options in the automation editor"><figcaption><p>Choose immediate, scheduled, recurring, date-relative, or event-based delivery.</p></figcaption></figure>

Select **Next** after setting the name and delivery time.

### Target the audience

Filters define which installed passes receive the notification. Select **Estimate** to check the number of targeted passes before sending.

Select **Add filter** to narrow the audience by:

* **Installation status** — target installed passes, Apple Wallet passes, or Google Wallet passes.
* **Template** — target a selected pass template.
* **Metadata** or **Identifiers** — target a specific data value or identifier.

Multiple filters always use an **AND** rule. Every selected condition must match. This rule cannot be changed.

<figure><img src="/files/xQ9MdXNb8elJY8Gzo0li" alt="Audience filter builder for a notification automation"><figcaption><p>Use filters to define the pass holders who receive the notification.</p></figcaption></figure>

### Write the notification message

Configure the Apple Wallet message. It appears on the lock screen when Apple Wallet sends the notification.

On Google Wallet, Google controls the notification text. The Wallet app notifies customers that a new message is available.

For multilingual passes, enable **translations**. Then select each language on the right to configure its message.

<figure><img src="/files/HF39I3WHrExPP0cNYKbS" alt="Translation toggle in the notification message editor"><figcaption><p>Enable translations to configure a message for each supported pass language.</p></figcaption></figure>

<figure><img src="/files/eq00YiynpSinCbYqnN6W" alt="Language selector in the notification message editor"><figcaption><p>Select a language to edit its localized notification message.</p></figcaption></figure>

Use the preview in the top-right corner to check the Apple Wallet and Google Wallet experience.

Notifications remain visible for seven days by default. During that period, recipients can view them on the back of the pass.

To change this duration, open **Wallet → Template → Editing → General → Advanced configuration**. Then update the notification duration.

### Configure delivery throughput

The default throughput suits most notifications. Increase it only when delivery must complete before a fixed time.

For example, set a suitable throughput before sending event access details. This helps deliver notifications before doors open.

Select **Next** to review the summary. Save the automation after confirming the audience and settings.

## Verify notification delivery

Use the pass-level notification timeline to confirm delivery and investigate reports of missing notifications. Open **Wallet → Passes → \[select a pass] → Notifications**.

The tab shows a full timeline of notifications sent to that pass, including:

* The timestamp and delivery status.
* The target platform: Apple Wallet or Google Wallet.
* The sent message and localized variants, such as `FR-FR`.

{% hint style="info" %}
Synchronization may take up to five minutes. The notification then appears in the **Notifications** tab.
{% endhint %}

## FAQ

<details>

<summary><strong>Can the same notification target Apple Wallet and Google Wallet?</strong></summary>

Yes. Installation-status filters can target Apple Wallet, Google Wallet, or both. The platforms handle lock-screen content differently.

</details>

<details>

<summary><strong>Why is the Google Wallet lock-screen text different?</strong></summary>

Google Wallet controls the notification text. It alerts customers that a new pass message is available. The message content is available in the pass.

</details>

<details>

<summary><strong>How can delivery be checked for one customer?</strong></summary>

Open the pass and select **Notifications**. The timeline shows the send time, delivery status, platform, and message content. Allow up to five minutes for synchronization.

</details>


# Consents & GDPR compliance

Mobile Wallet notifications: transactional, marketing, and GDPR consent.

Mobile wallets can surface contextual and campaign-driven notifications. Because some messages are marketing, consent must be managed correctly.

This page explains the difference between transactional and marketing notifications and the controls needed for GDPR compliance. For delivery mechanics, see [Push notifications](/guides-animation/engage-and-animate/automatisation/push-notifications).

## Transactional vs marketing notifications

{% tabs %}
{% tab title="Transactional" %}
Transactional notifications stem directly from a contract or loyalty-program membership. They must be necessary to deliver the service. Contract performance usually covers them, so marketing opt-in is not required.

<details>

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

* “You have earned 50 points.”
* “Your concert starts tomorrow at 8 PM.”
* “You have 3 entries remaining.”

</details>
{% endtab %}

{% tab title="Marketing" %}
Marketing notifications promote a product or service without a direct link to an existing contract. They are commercial prospecting and typically require explicit marketing opt-in.

<details>

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

* Update a promotional pass field to announce an offer.
* Send a Google Wallet message about a new collection.

</details>
{% endtab %}
{% endtabs %}

{% hint style="warning" %}
A prospect who downloads a pass without enrolling is not covered by contract performance. Any proactive notification is marketing outreach.
{% endhint %}

### Legal basis

A lawful basis is required for wallet notifications. Transactional notifications typically rely on contract performance under GDPR Article 6(1)(b). They must remain necessary to deliver the service.

Marketing notifications typically rely on consent under GDPR Articles 6(1)(a) and 7. Consent must be free, specific, informed, and unambiguous. Keep proof of consent and make withdrawal easy.

### Collect consent

Collect marketing consent before sending promotional notifications. Registration is a common collection point. Consent can also be captured on a pass-download landing page, website, or app.

Keep service and marketing choices separate. Store them as independent flags. Do not bundle both purposes into one “Wallet notifications” checkbox.

### Privacy policy and legal notices

Privacy information must explain that a wallet pass can generate notifications. It should state the triggers, distinguish service and promotional messages, describe processing purposes, and explain customer controls.

Mention the main triggers and expected frequency. Keep the information easy to scan.

## Best practices

1. **Classify every notification.** Decide if it is transactional or marketing.
2. **Separate consent flags.** Maintain independent service and marketing choices.
3. **Gate marketing sends.** Send promotions only to opted-in customers.
4. **Keep proof of consent.** Store timestamp, source, and privacy notice version.
5. **Make opt-out easy.** Provide a preference-management link.
6. **Test the full journey.** Validate capture, updates, notifications, and opt-out synchronization.

## Wallet notification settings

Customers control notifications globally and per pass. They can disable automatic updates, push notifications, and contextual presentation for an individual pass.

### Apple Wallet

Apple Wallet notifications are triggered by pass updates. Any visible field change can trigger a notification. Typical changes include points, tier, or event reminders.

For promotional content, reserve a dedicated pass field. Update only that field for marketing copy.

### Google Wallet

Google Wallet can notify through pass updates or its notifications API. This supports more flexible messaging, but frequency must remain controlled.

## How The Wallet Crew helps

The Wallet Crew supports consent-aware notification strategies. Brands can separate purposes, segment based on consent status, and activate campaigns conditionally.

The Wallet Crew acts as a data processor for wallet notification services. The brand remains responsible for the legal basis, consent collection and storage, privacy notices, and data-subject rights.

{% hint style="warning" icon="scale-balanced" %}
Marketing consent must be collected through the brand's own consent mechanisms. The Wallet Crew does not collect it on the brand's behalf.
{% endhint %}

## FAQ

<details>

<summary><strong>Is marketing opt-in required for points or balance updates?</strong></summary>

Points, balances, tiers, and similar status updates are usually transactional when they are necessary to deliver the service. Keep service and marketing choices separate.

</details>

<details>

<summary><strong>Can pure marketing messages be sent through Apple Wallet?</strong></summary>

Yes, but explicit opt-in is required. Apple Wallet has no standalone push API. A pass update, ideally to a dedicated promotional field, triggers the notification.

</details>

<details>

<summary><strong>Does the Apple or Google notification prompt count as marketing consent?</strong></summary>

No. That prompt controls device-level delivery only. Marketing consent must be collected separately through the brand's own flows.

</details>

<details>

<summary><strong>What consent evidence should be stored?</strong></summary>

Store the timestamp, capture channel, wording shown, and applicable privacy-notice version. Store withdrawals with the same rigor.

</details>

<details>

<summary><strong>Why did a wallet notification not appear?</strong></summary>

Check global and per-pass device settings first. Then validate the platform trigger. Apple Wallet needs a visible pass update. Google Wallet depends on the selected trigger method.

</details>


# Monitoring guides

Guides for wallet analytics, KPI definitions, event exports, external sync, and Insights API queries.

The Monitoring guides explain how wallet activity is measured in The Wallet Crew, how performance is reported, and how individual passes can be investigated when a case needs record-level review.

<table data-view="cards"><thead><tr><th>Title</th><th>Description</th><th data-card-target data-type="content-ref">Target</th></tr></thead><tbody><tr><td><i class="fa-chart-mixed">:chart-mixed:</i> <strong>Analytics dashboards</strong></td><td>Understand pass creation, installs, removals, wallet split, and source performance at a glance.</td><td><a href="/spaces/EsokFUBfsbM9mlwavmMB/pages/Sha3mwp9gZoWSrDtZqxX">/spaces/EsokFUBfsbM9mlwavmMB/pages/Sha3mwp9gZoWSrDtZqxX</a></td></tr><tr><td><i class="fa-list">:list:</i> <strong>Pass list</strong></td><td>Find a pass quickly by identifier, template, metadata, or date, then open its detail page.</td><td><a href="/spaces/EsokFUBfsbM9mlwavmMB/pages/JhpYx2FXuI7AI37Vp005">/spaces/EsokFUBfsbM9mlwavmMB/pages/JhpYx2FXuI7AI37Vp005</a></td></tr><tr><td><i class="fa-id-card">:id-card:</i> <strong>Pass details</strong></td><td>Review one pass in full, including its identifiers, state, metadata, and recorded history.</td><td><a href="/spaces/EsokFUBfsbM9mlwavmMB/pages/OTt68VLdy4YcqCAKGDPn">/spaces/EsokFUBfsbM9mlwavmMB/pages/OTt68VLdy4YcqCAKGDPn</a></td></tr><tr><td><i class="fa-gauge-max">:gauge-max:</i> <strong>KPI definitions</strong></td><td>Define the metrics used in the Analytics dashboards and interpret them consistently over time.</td><td><a href="/spaces/EsokFUBfsbM9mlwavmMB/pages/qABUXUMTMhbeioIZugHq">/spaces/EsokFUBfsbM9mlwavmMB/pages/qABUXUMTMhbeioIZugHq</a></td></tr><tr><td><i class="fa-radar">:radar:</i> <strong>What The Wallet Crew tracks</strong></td><td>Understand which wallet events The Wallet Crew tracks, how installs are counted, and where Apple and Google set limits.</td><td><a href="/spaces/EsokFUBfsbM9mlwavmMB/pages/3qE6DuaArugxUyXVY61E">/spaces/EsokFUBfsbM9mlwavmMB/pages/3qE6DuaArugxUyXVY61E</a></td></tr><tr><td><i class="fa-chart-simple-horizontal">:chart-simple-horizontal:</i> <strong>Report</strong></td><td>Export pass-level wallet events for campaign analysis, record-level review, and external reporting.</td><td><a href="/spaces/EsokFUBfsbM9mlwavmMB/pages/3CaaCadT7G2YQUTyAIG9">/spaces/EsokFUBfsbM9mlwavmMB/pages/3CaaCadT7G2YQUTyAIG9</a></td></tr><tr><td><i class="fa-plug">:plug:</i> <strong>Send wallet events to your tools</strong></td><td>Push install, uninstall, scan, and notification events to CRM, CDP, BI, and data warehouse tools in real time.</td><td><a href="/spaces/EsokFUBfsbM9mlwavmMB/pages/Sn9fD3CpybrE4P7ucEN5">/spaces/EsokFUBfsbM9mlwavmMB/pages/Sn9fD3CpybrE4P7ucEN5</a></td></tr><tr><td><i class="fa-gear-api">:gear-api:</i> <strong>Query your data — Insights API</strong></td><td>Query wallet events programmatically with the Insights API for dashboards, automated reporting, and BI workflows.</td><td><a href="/spaces/EsokFUBfsbM9mlwavmMB/pages/fkCovGXTWz5gjpAO4b5K">/spaces/EsokFUBfsbM9mlwavmMB/pages/fkCovGXTWz5gjpAO4b5K</a></td></tr></tbody></table>

Start with **Analytics dashboards** for a visual overview. Use **Pass list** and **Pass details** for record-level investigation when one pass needs to be found, checked, or escalated.

Use **KPI definitions** and **What The Wallet Crew tracks** to understand how metrics are calculated, how installs are counted, and where platform limits apply.

Use **Report** for record-level exports. When wallet event data needs to leave The Wallet Crew continuously or feed other systems, use **Send wallet events to your tools** and **Query your data — Insights API**. The first guide covers real-time delivery and sync patterns. The second covers programmatic querying for dashboards, BI workflows, and automated reporting.


# Analytics dashboards

Understand wallet, enrolment, and link performance in the Analytics section.

The Wallet Crew includes three dashboards in the **Analytics** section of the admin console. Each dashboard covers a different stage of the wallet programme lifecycle.

All dashboards include a date range picker. It defaults to **Last 30 Days**. The **Wallets** dashboard also supports filtering and CSV export.

<details>

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

* A retail brand compares wallet saves by acquisition channel after a campaign launch.
* An event organiser tracks enrolment form activity before a ticket release.
* An in-store team identifies which QR codes generate the most wallet saves.

</details>

## Wallets

**Location:** **Analytics** → **Wallets**

The **Wallets** dashboard gives a live overview of a wallet programme. It tracks issuance, adoption, removals, source performance, and wallet mix during the selected period.

Use it to assess campaign impact, spot unexpected changes, and compare results by source, template, or pass metadata.

### KPIs

The KPI tiles separate issuance, adoption, and churn. Each tile compares results with the previous equivalent period.

* **Passes Created** — Total pass records created during the period. Creation does not confirm wallet adoption.
* **Passes Installed** — Passes saved to Apple Wallet or Google Wallet during the period. This measures adoption.
* **Passes Uninstalled** — Passes removed from every device where they were installed. This measures churn.

Compare **Passes Created** and **Passes Installed** to understand [activation rate](/guides-monitoring/monitor/kpi-definitions). The rate is calculated as `Installed Passes ÷ Created Passes`.

{% hint style="info" %}
Passes Created ≠ Passes Installed. A created pass is not necessarily saved to a wallet.
{% endhint %}

### Charts

**Evolution of installations** shows daily installation volume. Use it to identify changes after sends, launches, or in-store campaigns.

**Pass Distribution** splits installations between Apple Wallet and Google Wallet. The wallet mix helps plan wallet-specific actions. Google Wallet limits pushes to three updates per pass every 24 hours.

### Source breakdown

The breakdown table compares the channels and pass dimensions that drive wallet saves. Its group-by selector defaults to **Medium**, which corresponds to `source.medium`.

#### Grouping options

Source groupings include:

* **Medium** — Distribution channels, such as `email-crm`, `ecomm`, or `trigger-crm`.
* **Tag** — Campaign or segment tags attached to the installation source.
* **URL** and **Host** — The exact page or domain containing the **Add to Wallet** button.

Any pass metadata field can also group results. For example, use `storeId` or `storeName` to compare stores, regions, partners, or segments.

#### Table columns

Source groupings show the source value and **Installed Passes**. Metadata groupings show the metadata value, **Created Passes**, **Installed Passes**, and [**Activation rate**](/guides-monitoring/monitor/kpi-definitions).

#### Filters and export

Use **Add filter** to focus on a template or metadata value. **Export** downloads the current table view as a CSV file.

### Date range

The date picker controls every tile, chart, and table on the dashboard. Percentage changes use the immediately preceding equivalent period. For example, a seven-day selection compares with the previous seven days.

## Enrolments

**Location:** **Analytics** → **Enrolments**

Enrolment metrics track customer profile activity driven by enrolment forms. Use this dashboard to monitor profile creation and updates during the selected period.

### KPIs

* **Customer Upserted** — Total profile create-or-update operations.
* **Customer Created** — Net-new customer profiles created.
* **Customer Updated** — Updates to existing customer profiles.

### Chart

**Customer enrolment over time** shows customer profile activity across the selected period.

## Links

**Location:** **Analytics** → **Links**

Links metrics track QR code and redirect link usage. Use this dashboard to measure in-store or on-site distribution performance.

### KPI

* **QR codes scanned** — Total scans during the selected period.

### Chart

**QR codes scanned over time** shows scan activity across the selected period.

### Breakdown table

The breakdown table shows which individual links or QR codes drove the most scans. It includes the following columns:

* **Key** — The link identifier.
* **Count** — The total number of scans.

## FAQ

<details>

<summary>Which date range applies to a dashboard?</summary>

The date range picker controls the full dashboard. It defaults to **Last 30 Days**. On **Wallets**, export uses the current table view.

</details>

<details>

<summary>How can Wallets focus on one pass template?</summary>

In **Analytics** → **Wallets**, select **Add filter** and narrow the dashboard to the required template.

</details>

<details>

<summary>Which dashboard measures QR code performance?</summary>

Use **Analytics** → **Links**. The dashboard shows total scans, scan activity over time, and results by link key.

</details>

<details>

<summary>Why are Passes Created often higher than Passes Installed?</summary>

Creation measures issuance. Installation measures adoption. A pass can be issued without being saved to a wallet.

</details>

<details>

<summary>Why can Passes Uninstalled stay low when removals happen?</summary>

The metric counts a pass only when every active installation is removed. A pass still installed on another device is not counted.

</details>


# Pass list

Find a pass quickly by identifier, template, metadata, or date, then open its detail page.

The pass list shows every pass in a programme. Use it to find a pass by any identifier, filter by template or date, and open the pass detail page for a full view of that pass's history.

<details>

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

* A support agent searches a loyalty number to answer a customer query.
* An operations manager filters by template and creation date to check a batch issue.
* A programme administrator opens a pass to verify its current state and history.

</details>

## How to open the pass list

The pass list is the starting point for finding and checking a pass. It brings every pass available in the account into one view.

{% stepper %}
{% step %}

### Open the back-office

Sign in to The Wallet Crew back-office.
{% endstep %}

{% step %}

### Go to **Wallet > Passes**

The list loads all available passes. By default, the newest updates appear first.
{% endstep %}
{% endstepper %}

## Finding a pass

The search and filter controls at the top of the list narrow the result set quickly. Start with the identifier already available in the customer case, then add template or date filters if needed.

**Filters available:**

* **Pass ID** — the internal platform identifier for the pass.
* **External ID** — any external identifier linked to the pass, such as a CRM customer ID, a loyalty number, or a booking reference. This is the most common way support teams locate a specific customer's pass.
* **Pass template** — narrows the list to passes created from one template.
* **Metadata fields** — filters by any metadata field defined on the passes, such as `storeId` or `programmeId`. These fields depend on the programme setup and can vary from one programme to another.
* **Creation date** — shows only passes created within a date range.
* **Last updated** — shows only passes updated within a date range.

{% hint style="info" %}
To find a pass for a specific customer, filter by **External ID** using the identifier sent when the pass is created — for example, a CRM ID, loyalty number, or booking reference.
{% endhint %}

## Columns

The default columns give a quick operational view of each pass.

| Column              | What it shows                                       |
| ------------------- | --------------------------------------------------- |
| Pass ID             | The internal platform identifier                    |
| Creation date       | When the pass record was created                    |
| Last updated        | When the pass was last modified or updated          |
| Template            | Which pass template the pass was created from       |
| External ID         | The external identifiers linked to this pass        |
| Installation status | Whether the pass is currently installed in a wallet |

Use the column selector to add or remove columns. Metadata fields are available as extra columns, and the selected layout is saved in the browser.

## Opening a pass

Click any row in the list to open the pass detail page for that pass.

For what can be reviewed once the pass is open, see [Pass details](/guides-monitoring/monitor/pass-details).

## FAQ

<details>

<summary>Which filter should be used first for a customer case?</summary>

**External ID** is usually the fastest starting point. It matches the identifier sent from the source system when the pass was created.

</details>

<details>

<summary>Why does filtering by External ID show several rows for the same identifier?</summary>

The back-office shows every pass created with that External ID. An External ID does not guarantee a one-to-one match with a pass.

Multiple rows usually result from test enrolments or repeated API calls. To identify the active pass, check the **Installation status** column, then compare the most recent **Last updated** value.

For the technical model behind external identifiers and data retrieval, see [Pass data and sync](/developers-guides/pass-architecture/pass-data-and-sync).

</details>

<details>

<summary>Why do metadata filters differ between programmes?</summary>

Metadata fields come from each programme's pass setup. One programme may use `storeId`, while another may use `eventId` or `membershipTier`.

</details>

<details>

<summary>Why do the visible columns look different on another browser?</summary>

The column setup is saved in the local browser. A different browser or device can show a different saved layout.

</details>


# Pass details

Review one pass in full, including its identifiers, state, metadata, and recorded history.

To find a specific pass, see [Pass list](/guides-monitoring/monitor/pass-list).

The pass detail page gives a complete view of one pass — its current state, the data it holds, its notification history, and its full event log. It also makes it possible to trigger a pass update or send a notification directly from this page.

<details>

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

* A support agent checks whether a customer's pass is still installed and re-sends the QR code.
* An operations manager reviews the event history after a push update.
* A programme administrator verifies metadata and notification history before escalating a case.

</details>

## The four tabs

The detail page is organised into four tabs. Each tab answers a different operational question.

### General

The **General** tab shows the current state of the pass. It is the fastest place to confirm the main operational details.

The tab includes:

* **Template** — which pass template this pass was created from.
* **Title / Subtitle** — the values currently shown in the pass header fields.
* **Creation date** — when the pass record was created on the platform.
* **Last updated** — when the pass was last modified.
* **Installation status** — whether the pass is installed in Apple Wallet, Google Wallet, both, or neither. Apple and Google installation status appear separately.
* **Active installations** — the number of wallets where the pass is currently installed. For Apple, this counts individual devices, including Apple Watch. For Google, this counts Google accounts.

{% hint style="info" %}
An active installation count of `0` means the pass has been removed from all wallets. The pass record still exists on the platform — it has not been deleted.
{% endhint %}

### Data

The **Data** tab shows all data associated with the pass. This is useful when the visible pass content needs to be checked against the underlying record.

The data is grouped into three categories:

* **Additional data** — information stored directly on the pass record. These values are usually set when the pass is created or updated.
* **External data** — information pulled in from connected source systems. This shows the latest data available when the pass was last refreshed.
* **Metadata** — extra fields attached to the pass, such as `storeId`, `programmeId`, or any custom field used for filtering and reporting.

### Notifications

The **Notifications** tab lists every push notification sent to this pass. Use it to confirm what message was sent and when it was sent.

Each row shows:

* **Date** — when the notification was sent.
* **Message** — the notification content that was sent.
* **Device type** — Apple or Google.

{% hint style="info" %}
Delivery confirmation is not available. Apple and Google do not expose whether a notification was received by the device.
{% endhint %}

### History

The **History** tab shows the complete event log for this pass. Use it to understand what happened, in which order, and with which recorded data.

All platform events for this pass are listed, including:

| Event                 | What it means                                              |
| --------------------- | ---------------------------------------------------------- |
| Pass:Created          | The pass record was created on the platform                |
| Pass:Installed        | A customer added the pass to Apple Wallet or Google Wallet |
| Pass:Uninstalled      | A customer removed the pass from their wallet              |
| Pass:Updated          | The pass data was changed                                  |
| Pass:UpdateSent       | A push update was delivered to a device                    |
| Pass:Scanned          | The pass barcode was scanned at a reader                   |
| Pass:NotificationSent | A push notification was sent to this pass                  |

Each event row shows the event timestamp and all data recorded with the event.

The history is complete. All events are shown with no time-limit cutoff.

For bulk export across many passes, use [Report](/guides-monitoring/monitor/report).

## Actions

Three actions are available from the top of the pass detail page. These actions help resolve common support and operations cases without leaving the page.

### Push update

**Push update** refreshes the pass using the latest available data. It always updates the pass record on The Wallet Crew.

A confirmation toast appears when the update is queued.

#### Push notification behavior

A pass update has two separate outcomes: a backend update and a device notification.

The backend always updates the pass, whether or not it is installed. Pass identifiers, metadata, and timestamps are updated and stored on The Wallet Crew.

A device notification is sent only when the pass is currently installed in Apple Wallet or Google Wallet. No device notification is sent when the pass is uninstalled.

Backend updates persist. If the pass is installed again later, the wallet receives the latest version stored on The Wallet Crew.

Use [Pass:Installed and Pass:Uninstalled events](/developers-guides/integration-guides/wallet/pass-lifecycle#wallet-removal) to track wallet installation and removal.

### Send notification

**Send notification** sends a push notification to all devices where this pass is installed. Use this to alert the customer, for example to inform them of a balance change or a new offer.

This action does not rebuild the pass content.

### View QR code

**View QR code** displays the pass's Add-to-Wallet QR code. Use this to re-send the install link to a customer, for example by screenshot or email.

## FAQ

<details>

<summary>When should the General tab be checked first?</summary>

Start with **General** when the goal is to confirm whether the pass exists, which template it uses, when it changed last, and whether it is still installed.

</details>

<details>

<summary>What is the difference between Data and History?</summary>

**Data** shows the current values attached to the pass. **History** shows the sequence of events that happened to that pass over time.

</details>

<details>

<summary>When should Report be used instead of Pass details?</summary>

Use **Pass details** for one-pass investigation. Use [Report](/guides-monitoring/monitor/report) when event data is needed in bulk across many passes.

</details>

<details>

<summary>Can I use failed updates to detect uninstalled passes?</summary>

No. Updates never fail because a pass is uninstalled. The backend update always succeeds. Device notification is conditional on an active Apple Wallet or Google Wallet installation.

Use [Pass:Installed and Pass:Uninstalled events](/developers-guides/integration-guides/wallet/pass-lifecycle#wallet-removal) to track wallet removal.

</details>


# KPI definitions

Define the metrics used in Analytics dashboards and how to interpret them over time.

This page defines every metric used in the Analytics dashboards so data can be interpreted accurately and compared over time.

<details>

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

* A marketing team compares **Passes Created** and **Activation rate** after an email campaign to see whether distribution reached wallets efficiently.
* An operations team reviews **Passes Uninstalled** and **Churn rate** after a seasonal expiry wave to understand whether renewal is working.
* A growth team checks installs by **Medium**, **Tag**, and **Host** to identify which entry points drive the most wallet adoption.

</details>

## Core metrics

The metrics below are the main reference points used across [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards). The summary table helps with quick lookup, while the definitions below explain how to interpret each number in context.

| Metric                                                                | Formula                                                                              | Where to find it                                                                                                         |
| --------------------------------------------------------------------- | ------------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
| [Passes Created](/guides-monitoring/monitor/analytics-dashboards)     | `COUNT(Pass:Created)` in the selected period                                         | [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards) summary tiles                                    |
| [Passes Installed](/guides-monitoring/monitor/analytics-dashboards)   | `COUNT(Pass:Installed)` in the selected period                                       | [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards) summary tiles                                    |
| [Passes Uninstalled](/guides-monitoring/monitor/analytics-dashboards) | `COUNT` of passes whose active installation count reached `0` in the selected period | [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards) summary tiles                                    |
| [Activation rate](/guides-monitoring/monitor/analytics-dashboards)    | `(Passes Installed ÷ Passes Created) × 100`                                          | [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards) breakdown table                                  |
| [Churn rate](/guides-monitoring/monitor/analytics-dashboards)         | `(Passes Uninstalled ÷ Active installations at start of period) × 100`               | Used as an interpretation metric alongside [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards) tiles |

### [Passes Created](/guides-monitoring/monitor/analytics-dashboards)

**Passes Created** is the total number of pass records created in the platform during the selected period.

The formula is `COUNT` of `Pass:Created` events in the period.

This metric measures distribution volume. Compare it to **Passes Installed** to understand what share of issued passes reached a wallet.

### [Passes Installed](/guides-monitoring/monitor/analytics-dashboards)

**Passes Installed** is the number of passes added to Apple Wallet or Google Wallet during the selected period.

The formula is `COUNT` of `Pass:Installed` events in the period.

On Apple, this counts per device. On Google, this counts per account. For the full tracking model, see [What The Wallet Crew tracks](/guides-monitoring/monitor/what-the-wallet-crew-tracks).

This is the primary engagement signal. A pass in a wallet can receive notifications, be scanned, and deliver ongoing value.

### [Passes Uninstalled](/guides-monitoring/monitor/analytics-dashboards)

**Passes Uninstalled** is the number of passes fully removed from all wallets during the selected period.

The formula is `COUNT` of passes where active installation count reached `0` during the period.

Removing a pass from one device does not count as uninstalled if it remains on another device.

This is the primary churn signal. Track it alongside **Passes Installed** to understand net wallet base change.

### [Activation rate](/guides-monitoring/monitor/analytics-dashboards)

**Activation rate** is the share of created passes that have been installed at least once.

The formula is `(Passes Installed ÷ Passes Created) × 100`.

Example: `23,500 installed ÷ 28,400 created = 82.7% activation rate`.

This metric measures distribution effectiveness. A low rate means passes are being created but not reaching wallets. Review the distribution channel and the friction in the **Add to Wallet** flow.

Email distribution typically yields `20–40%`. Contextual in-app distribution can exceed `70%`.

### [Churn rate](/guides-monitoring/monitor/analytics-dashboards)

**Churn rate** is the share of active pass holders who removed their pass during the period.

The formula is `(Passes Uninstalled ÷ Active installations at start of period) × 100`.

Elevated churn often follows a campaign with irrelevant content, or pass expiry without renewal. Investigate spikes against the campaign calendar.

## Source breakdown metrics

These metrics explain where installed passes came from. They help compare channels, campaigns, and page-level entry points inside [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards).

### [Installed Passes by Medium](/guides-monitoring/monitor/analytics-dashboards)

**Installed Passes by Medium** groups installations by distribution channel.

Use this to compare channels such as email, ecommerce, or store distribution. `Not specified` means the pass was installed without a tracked source, such as device transfer or sharing.

### [Installed Passes by Tag](/guides-monitoring/monitor/analytics-dashboards)

**Installed Passes by Tag** groups installations by campaign or segment tag.

Use this to compare campaign variants, audiences, or partner-specific distributions. Tags are set when the distribution link is generated.

### [Installed Passes by URL / Host](/guides-monitoring/monitor/analytics-dashboards)

**Installed Passes by URL / Host** groups installations by the page URL or domain where the **Add to Wallet** button was displayed.

Use this to compare landing pages, ecommerce flows, and domains. It helps identify which entry points drive wallet adoption most efficiently.

## Understanding the % change indicator

Every KPI tile compares the selected period against the equivalent prior period. A **Last 30 Days** view is compared with the previous 30 days.

* Green arrow up = improvement versus prior period
* Red arrow down = decline versus prior period

For **Passes Uninstalled**, an increase is shown in red because more churn is a worse outcome.

## FAQ

<details>

<summary>Why can Passes Installed be higher than expected on Apple Wallet?</summary>

Apple counts installations per device. The same person can generate more than one installation by adding a pass to multiple devices or by moving to a new phone.

</details>

<details>

<summary>Why does Passes Uninstalled not always match simple removal events?</summary>

A pass is counted as uninstalled only when its active installation count reaches zero. If it still exists on another device, it is not fully uninstalled yet.

</details>

<details>

<summary>What does a low activation rate usually mean?</summary>

It usually means passes are being issued, but not enough people complete the **Add to Wallet** step. The first areas to review are channel quality, visibility, and friction in the install flow.

</details>


# What The Wallet Crew tracks

Understand which wallet events The Wallet Crew tracks, how installs are counted, and where Apple and Google set limits.

The Wallet Crew tracks pass activity through events generated at each meaningful moment in the pass lifecycle. This page explains what is tracked, how installation counting works, and what cannot be tracked, along with the Apple and Google platform rules behind those limits.

This makes it easier to configure reports, align expectations across teams, and decide which signals can be used for campaign analysis or operational follow-up.

<details>

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

* A marketing team checks whether wallet installs can be tied back to email, ecommerce, or store traffic.
* An operations team confirms whether a pass removed from one device is treated as fully uninstalled or still active elsewhere.
* A CRM team validates which wallet signals can be synced automatically and which ones do not exist on Apple or Google.

</details>

## What The Wallet Crew tracks

The Wallet Crew records the lifecycle events that wallet platforms expose and that the pass flow can reliably generate. Some events describe the pass itself, while others describe what happened on a wallet or device.

### Pass creation

A pass record is created in The Wallet Crew when a pass is issued. This can happen through the API, after account creation, when a pass layout is displayed, or through a connector.

A created pass exists in the platform even if no one has added it to a wallet yet. Creation shows issuance. It does not confirm adoption.

### Pass installation

The platform tracks when a pass is added to a wallet. Installation counting works differently on Apple Wallet and Google Wallet because each provider defines installation in its own way.

* **Apple Wallet** tracks each device individually. Adding the same pass to an iPhone and an Apple Watch counts as two installations. Moving to a new phone also creates a new installation.
* **Google Wallet** tracks installation per Google account. Multiple Android devices connected to the same account count as one installation.

Two counters exist for each pass:

* **Active installations** — decreases when the pass is removed from a wallet
* **Total installations** — cumulative and never decreases

These counters serve different purposes. Active installations show how many valid wallet presences still exist. Total installations show how many times the pass has ever been installed.

### Installation source

When a customer taps an **Add to Wallet** button, The Wallet Crew captures the source context of that action. This helps connect wallet adoption back to the campaign or page that triggered it.

* **Medium** — the distribution channel, such as email, ecommerce, or store
* **Tag** — custom campaign or segment tags
* **URL** — the exact page where the button was displayed
* **Host** — the domain of that page

Source data is not available when a pass is installed through device transfer, phone sharing, or other system-level mechanisms. In those cases, the wallet platform completes the install without sending the original acquisition context back.

### Pass removal

The Wallet Crew tracks when a pass is removed from a wallet. Each removal decreases the active installation count.

When the active installation count reaches zero, the pass is fully uninstalled. This matters for churn analysis because a pass removed from one device may still remain active on another.

### Updates sent

Each push update delivered to a device is recorded. This makes it possible to review update activity over time and understand how often pass content is being refreshed.

### Scans

Each barcode scan is recorded, including the scanned data and scan type. This makes scan history useful for redemption and operational verification.

### Push notifications sent

Each push notification sent to a device is recorded, including its content and the wallet provider. This confirms that the notification was sent through the platform.

## What cannot be tracked

{% hint style="warning" %}
These are privacy decisions made by Apple and Google to protect customers, not limitations of The Wallet Crew. Every wallet platform faces the same constraints.
{% endhint %}

Some signals seem natural to expect, but the wallet providers do not expose them. When the platform does not receive the data, it cannot report it later.

| What might be expected      | Why it is not available                                                                                                          |
| --------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Pass opens or views         | Apple and Google do not report whether a customer viewed a pass. There is no equivalent of an email open rate for wallet passes. |
| Push notification tap rates | Delivery can be confirmed. Whether the customer tapped the notification is not reported by either platform.                      |
| Geo-trigger activations     | Location triggers fire on the device. The device does not report back to the issuer when this happens.                           |
| Per-device count on Google  | Google tracks installation per account. Three Android devices on one account still count as one installation.                    |

## Pass state — voided and expired

The Wallet Crew does not impose a fixed status model on passes. Pass state comes from source data and is mapped through the template engine to the Apple and Google wallet attributes that control display and behaviour.

| What needs to be expressed | Apple                                                         | Google                                                                      |
| -------------------------- | ------------------------------------------------------------- | --------------------------------------------------------------------------- |
| Pass is used or consumed   | `voided: true` — appears grayed out in Apple Wallet           | `state: COMPLETED` or `INACTIVE` — moves to the **Expired** section         |
| Pass has expired over time | `expirationDate` — removed from active passes after this date | `validTimeInterval` — automatically moves to expired when the interval ends |

When the source data changes, The Wallet Crew updates the pass and pushes the change to the device automatically. This keeps the wallet state aligned with the business state without manual intervention.

## Using this data

Tracked wallet events are useful across marketing, operations, and CRM workflows. They help teams act on real lifecycle signals rather than assumptions.

* Trigger a CRM update when a pass is first installed to confirm wallet opt-in
* Identify customers who have uninstalled their pass as a churn signal
* Attribute installs back to source channel with **Medium** and **Tag**
* Use scan events to confirm redemption at point of sale

For downstream use, see [Query your data — Insights API](/guides-monitoring/monitor/query-your-data-insights-api) for programmatic queries and [Send wallet events to your tools](/guides-monitoring/monitor/sync-pass-installation-status-to-your-crm) for real-time delivery.

## FAQ

<details>

<summary>Why can one person generate more than one installation?</summary>

On Apple Wallet, installation is counted per device. The same person can install a pass on an iPhone and an Apple Watch, or generate a new installation after changing phone.

</details>

<details>

<summary>Why is a pass not counted as uninstalled after one removal?</summary>

A pass is counted as uninstalled only when its active installation count reaches zero. If it still exists on another device or wallet context, it remains active.

</details>

<details>

<summary>Why is the install source sometimes missing?</summary>

Source data is captured when the install starts from a tracked **Add to Wallet** button. It is not available for device transfer, phone sharing, or other system-level install paths.

</details>

<details>

<summary>Can The Wallet Crew track whether a pass was opened or viewed?</summary>

No. Apple and Google do not report pass opens or views back to issuers. This is a wallet platform privacy rule, not a The Wallet Crew limitation.

</details>


# Report

Export pass-level wallet events for campaign analysis, CRM enrichment, and external reporting.

The **Report** page exports pass-level event data, including installs, updates, removals, scans, and notifications, filtered by date range and pass attributes. It is the right view when the underlying records matter more than the totals.

Use this page to analyse campaign performance in detail, enrich CRM records with wallet activity, or feed wallet data into external reporting tools. For aggregated trends and KPI summaries, use [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards).

<details>

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

* A marketing team exports install events after a campaign send to compare channel performance by `Medium` or `Tag`.
* An operations team exports uninstall events to identify customers who no longer keep the pass in their wallet.
* A BI team exports scan events to study redemption patterns by location, store, or time window.

</details>

## What data can be exported

The **Report** page exports one row per event. This makes it useful for detailed analysis, reconciliation, and downstream processing.

The following event types are available for export:

* **Pass:Created** — when a pass record was created
* **Pass:Installed** — when a pass was added to Apple Wallet or Google Wallet, including installation source details such as **Medium**, **Tag**, **URL**, and **Host**
* **Pass:Uninstalled** — when a pass was removed from all wallets
* **Pass:Updated** — when pass data changed
* **Pass:UpdateSent** — when a push update was delivered to a device
* **Pass:Scanned** — when a pass barcode was scanned
* **Pass:NotificationSent** — when a push notification was sent

Each export focuses on event history rather than summary counts. That makes it possible to trace what happened, when it happened, and which pass was affected.

For the meaning and limits of each tracked event, see [What The Wallet Crew tracks](/guides-monitoring/monitor/what-the-wallet-crew-tracks).

## How to export

The export flow is designed for quick filtering and repeatable reporting. Start with the time period, then narrow the scope to the events and pass records that matter.

{% stepper %}
{% step %}

### Select a date range

Choose the period to analyse. The selected range controls which events are included in the file.
{% endstep %}

{% step %}

### Choose the event types

Select the event types to include in the export. This keeps the file focused on the activity needed for the task.
{% endstep %}

{% step %}

### Apply filters

Filter by template or by pass metadata field value. This helps isolate a campaign, a pass family, a region, a store group, or any other segment tracked in pass data.
{% endstep %}

{% step %}

### Export the file

Click **Export** to download the current selection as a CSV file. The file can then be opened in spreadsheet tools or loaded into CRM and BI workflows.
{% endstep %}
{% endstepper %}

## Using exported data

Exports are most useful when a team needs to work at record level. They support operational follow-up, campaign review, and external analysis without relying on aggregated dashboards alone.

### CRM sync

Export install events and match them on a stable pass identifier. This makes it possible to enrich contact records with wallet opt-in or installation status.

### Campaign attribution

Filter install events by **Medium** or **Tag** to compare which channels drove the most installs for a campaign. This helps connect wallet adoption back to the source that generated it.

### Churn detection

Export uninstall events to identify customers who removed their pass. This can support churn analysis, win-back actions, or journey adjustments.

### Scan analytics

Export scan events to analyse redemption patterns by location or time of day. This is useful when the goal is to understand not just adoption, but real pass usage.

## When to use Report vs Analytics dashboards

**Report** is the detailed view. It exports the individual rows behind wallet activity.

**Analytics dashboards** are the summary view. They show trends, totals, and KPI changes for faster monitoring. Use [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards) when the goal is to review programme performance at a glance.


# Send wallet events to your tools

Send wallet install, uninstall, scan, and notification events to CRM, CDP, BI, and data warehouse tools with webhooks, custom connectors, the Pass API, or the Insights API.

The Wallet Crew does not lock data inside the platform. Every event emitted across a wallet programme can be sent to a CRM, CDP, BI tool, or data warehouse. Four integration paths cover most needs: **webhooks**, a **custom connector**, the **Pass API**, and the **Insights API**.

{% hint style="info" %}
Your wallet data belongs to you. The Wallet Crew emits every pass event in real time — you decide where it goes and what you do with it.
{% endhint %}

<details>

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

* A CRM or CDP team sends `Pass:Installed` events into Braze or Salesforce to trigger onboarding journeys after wallet adoption.
* A BI team streams wallet events into BigQuery or Snowflake, then uses the Insights API to monitor weekly installs by `Medium`, `Tag`, or `Host`.
* An ecommerce team keeps real-time install status in its stack with webhooks, then uses a daily Pass API backfill to repair drift after outages.

</details>

### What “installation status” means

Installation status is a lifecycle signal emitted when a user adds or removes a pass. It covers installs and removals on Apple Wallet and Google Wallet, and each wallet can change state independently.

This matters because install state is wallet-specific. The same customer can install a pass on Apple Wallet, Google Wallet, or both, and each removal event must be interpreted in that context.

{% hint style="info" %}
Make sure each pass includes a stable external identifier, such as `customerId` or `email`. That identifier is used to reconcile events with records in the rest of the stack.
{% endhint %}

### Choose the right sync method

If you want real time updates, use **webhooks** or a **custom connector**.

If you prefer batch jobs or backfills, use the **Pass API**.

If you mainly need counts and trends, use **Insights API**.

### Start with Insights API for aggregate analysis

If there is no need for per-customer sync and the goal is to query trends and aggregate data, start with the **Insights API**. It is the fastest path to questions such as “how many passes were installed this week by medium?”

Use Insights when counts, trends, and grouped analysis matter more than record-level updates. Query events such as `Pass:Installed` and `Pass:Uninstalled` with KQL.

Next step: set up authentication and run a first query.

See [Insights API](/developers-guides/integration-guides/insights-api).

For aggregate analysis in the back office, use [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards). For pass-level records, use [Report](/guides-monitoring/monitor/report).

### Decide what to sync into your tools

Start by defining the “truth” the stack should store. Most teams keep both a simple status and a few timestamps in the CRM or CDP.

You usually want an overall field, plus per-wallet fields. That lets you segment without losing detail.

Common fields:

* `walletStatus`: `none`, `apple`, `google`, `both`
* `appleWalletInstalledAt`: timestamp, optional
* `googleWalletInstalledAt`: timestamp, optional
* `walletLastChangedAt`: timestamp
* `walletLastEvent`: installed or uninstalled

{% hint style="warning" %}
Treat events as **at-least-once delivery**. Expect duplicates and out-of-order delivery.
{% endhint %}

### Reconcile events to records in your stack

Your sync needs a join key. Use a stable external identifier stored on the pass.

Good identifiers are `customerId`, `accountId`, or a normalized email. Avoid identifiers that can change frequently.

When an event arrives, resolve it to one record in the stack. Then update the per-wallet flags and the overall status kept in the stack.

### Understand the edge cases

Installation is wallet-specific. A single customer can install on Apple and Google.

Uninstall also stays wallet-specific. An Apple uninstall does not imply Google uninstall.

Some customers reinstall quickly. Use timestamps to avoid status flapping in downstream tools.

### Option 1 — Webhooks (real time, lowest effort)

Webhooks push events to your endpoint as they happen. Subscribe to `Pass:Installed` and `Pass:Uninstalled`.

Next step: configure your webhook endpoint and validate signatures.

See [Webhooks](/developers-guides/integration-guides/webhooks).

### Option 2 — Custom connector (real time, custom payload)

Use a custom connector when the default webhook payload is not enough.

It’s the right choice for custom payload shapes. It’s also useful for custom auth (API key, OAuth) or extra logic.

Typical logic includes routing, enrichment, throttling, and retries.

Next step: implement `OnPassInstalled` and `OnPassUninstalled`.

See [Pass installation and uninstallation hooks](/connectors/custom-connector/installation-changed-extensibility).

### Option 3 — Pass API (batch sync + backfills)

Use the Pass API when you want to periodically sync installation state.

This is also the best choice for rebuilding state in downstream tools after downtime.

Start from the API reference. Look for pass list endpoints that can be filtered by installation status.

#### Backfill pattern that works well

Run a scheduled job that recomputes source-of-truth status from the Pass API. Most teams run it daily.

Use your real-time events for speed. Use the backfill for consistency.

If the stack and passes disagree, trust the Pass API. Then repair the downstream record and keep going.

### A pragmatic end-to-end workflow

{% stepper %}
{% step %}

### 1) Add a stable identifier to every pass

Pick one identifier. Use the same field on every pass.
{% endstep %}

{% step %}

### 2) Send real-time events to your stack

Use webhooks for most setups. Use a custom connector if you need a different payload.
{% endstep %}

{% step %}

### 3) Update fields and segments in your tools

Update per-wallet flags and timestamps. Recompute the overall `walletStatus`.
{% endstep %}

{% step %}

### 4) Backfill regularly

Schedule a Pass API job. Use it to repair drift and cover downtime.
{% endstep %}

{% step %}

### 5) Track adoption with Insights

Use Insights for trends and monitoring. Validate that installs and uninstalls match expectations.
{% endstep %}
{% endstepper %}

### Troubleshooting

If you do not see events, start with signature validation. Then check endpoint availability and retry handling.

If you see duplicates, add idempotency in the downstream write path. Use the most recent timestamp as the tie-breaker.

If you cannot match events to customers, you are missing an identifier. Add it to the pass data, then backfill to repair history.

### FAQ

<details>

<summary>Which option should be used first?</summary>

Start with the **Insights API** when only aggregate trends matter. Start with **webhooks** when events need to reach a CRM, CDP, or automation tool in real time. Add the **Pass API** when a reliable backfill is also needed.

</details>

<details>

<summary>Why are both real-time events and a batch backfill often used together?</summary>

Real-time delivery keeps journeys, alerts, and segments fresh. A scheduled Pass API backfill repairs drift caused by retries, outages, or temporary downstream failures.

</details>

<details>

<summary>Why is a stable identifier mandatory?</summary>

Wallet events are only useful downstream when they can be matched to the correct record. A stable identifier, such as `customerId` or a normalized email, makes reconciliation reliable across webhooks, connectors, and batch jobs.

</details>

<details>

<summary>Can the same customer appear as installed on both Apple and Google?</summary>

Yes. Installation is wallet-specific. The same customer can hold the same pass in Apple Wallet and Google Wallet, so downstream models should keep per-wallet fields as well as an overall status.

</details>


# Query your data — Insights API

Query wallet events programmatically with the Insights API for custom dashboards, automated reporting, and BI workflows.

The [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards) show wallet data visually. The **Insights API** gives programmatic access to that same data, so teams can build custom dashboards, feed BI tools, run ad hoc analysis, or automate reporting.

{% hint style="info" %}
No code is required to export data. The [Report](/guides-monitoring/monitor/report) page lets teams export event data as CSV from the back office.
{% endhint %}

<details>

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

* A marketing team compares install volume by `Medium` after a CRM campaign.
* An operations team tracks scans per store and monitors uninstall trends by programme.
* A BI team pulls wallet events into Tableau, Looker, or Power BI for weekly reporting.

</details>

## What is the Insights API?

The Insights API is a query interface for wallet events stored in The Wallet Crew platform. Every tracked event is queryable, including pass creations, installs, uninstalls, scans, notifications, and updates. It is the right choice when the back-office dashboard is not enough, such as for custom date ranges, custom groupings, BI ingestion, or automated reports.

## What you can query

The Insights API covers the same operational events used across monitoring and reporting. Each event answers a different business question.

| Event                   | What it captures                                                                                                    | Example question you can answer                            |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- |
| `Pass:Created`          | When a pass record was created                                                                                      | How many passes were issued this month per store?          |
| `Pass:Installed`        | When a pass was added to Apple Wallet or Google Wallet, with source data such as `Medium`, `Tag`, `URL`, and `Host` | Which email campaign drove the most installs last week?    |
| `Pass:Uninstalled`      | When a pass was fully removed from all wallets                                                                      | What is the uninstall rate by programme?                   |
| `Pass:Updated`          | When pass data was changed                                                                                          | How many passes were updated after the last campaign?      |
| `Pass:UpdateSent`       | When a push update was delivered to a device                                                                        | Are updates reaching devices reliably?                     |
| `Pass:Scanned`          | When a pass barcode was scanned                                                                                     | How many scans per day happened at each location?          |
| `Pass:NotificationSent` | When a push notification was sent                                                                                   | How many notifications were sent per programme this month? |

## Filters available

All queries support filtering by date range, pass template, event type, and source of installation. Source filters include `Medium`, `Tag`, `URL`, and `Host`.

Any pass metadata field can also be used as a filter. That includes business fields such as `storeId`, `programmeId`, region, or any custom metadata stored on the pass.

## How it relates to Analytics dashboards

{% hint style="info" %}
The **Analytics** dashboards are built on the Insights API. Everything visible in the dashboards can also be queried directly through the API, with more flexibility on groupings, filters, and date ranges.
{% endhint %}

For a no-code view of the same data, use [Analytics dashboards](/guides-monitoring/monitor/analytics-dashboards). To push events to external tools in real time, see [Send wallet events to your tools](/guides-monitoring/monitor/sync-pass-installation-status-to-your-crm).

## Getting started

The fastest path is to authenticate, inspect the available endpoints, and run a first aggregate query.

{% stepper %}
{% step %}

### 1. Authenticate

Use the API key in the `X-API-KEY` header.

```http
X-API-KEY: <API_KEY>
```

{% endstep %}

{% step %}

### 2. Explore the available endpoints

Use the [Insights API](/developers-guides/integration-guides/insights-api) to inspect endpoints, parameters, and response shapes.
{% endstep %}

{% step %}

### 3. Start with a simple query

Begin with a count of `Pass:Installed` events over the last 30 days. Group the result by `Medium` to see which acquisition source drove the most wallet adds during the period.

This first query gives a quick validation that authentication works and that source data is available on the programme.
{% endstep %}
{% endstepper %}

## Common use cases

Most teams start with one recurring reporting need, then expand to deeper analysis. The same event stream can support both operational monitoring and BI workflows.

* Feed installation and uninstall counts into Tableau, Looker, or Power BI.
* Automate a weekly report of programme performance by store or region.
* Build a custom activation funnel by correlating `Pass:Created` with `Pass:Installed`.
* Query scan events to build a redemption analytics view.
* Validate campaign delivery by comparing `Pass:NotificationSent` with install spikes.

## FAQ

<details>

<summary>When should the Insights API be used instead of Analytics dashboards?</summary>

Use **Analytics dashboards** for a quick visual read of programme performance. Use the **Insights API** when custom filters, custom groupings, BI ingestion, or automated reporting are needed.

</details>

<details>

<summary>Does the Insights API expose the same data as the dashboard?</summary>

Yes. The Analytics dashboards are built on the same event data. The API adds more flexibility for query shape, time range, and downstream use.

</details>

<details>

<summary>Is code required to access wallet event data?</summary>

No. The [Report](/guides-monitoring/monitor/report) page supports CSV export from the back office. The Insights API is useful when a programmable workflow is needed.

</details>


# Scan Guides

Every pass eventually needs to be checked — at checkout, at the door, or at a redemption counter. The Scan & validate tools cover how to read and act on wallet passes in the real world, with guidance

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h3>Scan &#x26; validate</h3></td><td>Read barcodes, QR codes, and NFC passes at checkout, entry, or redemption points — choose the right hardware and validate passes reliably.</td><td><a href="/files/TCHU1oWbxpjyjUmCLPEs">/files/TCHU1oWbxpjyjUmCLPEs</a></td><td><a href="/pages/crYH3jSoyROCwO8Q3DX6">/pages/crYH3jSoyROCwO8Q3DX6</a></td></tr><tr><td><h3>Scanner</h3></td><td>Pick the right scanner for wallet passes: 2D imagers vs laser scanners, 1D vs 2D codes, and a practical checklist for production readiness.</td><td><a href="/files/4hoFYyiVviFKuomf6haU">/files/4hoFYyiVviFKuomf6haU</a></td><td><a href="/pages/O6gdiZOJngTZUNmeOJ4p">/pages/O6gdiZOJngTZUNmeOJ4p</a></td></tr></tbody></table>

The core challenge is simple: wallet passes are displayed on a phone screen, and not every scanner reads screens well. **Scanner** walks through the practical side of this — why 2D imagers are typically the right choice over laser scanners, the difference between 1D barcodes (fast, compact identifiers) and 2D codes like QR (more data, better at short range and odd angles), and a selection checklist covering symbology support, screen brightness, cracked screens, and real-world throughput testing.

Whether you're validating a loyalty scan at POS, checking tickets at an event entrance, or redeeming a gift card, getting the hardware and scanning logic right from day one avoids costly read-rate issues once you're live.


# Pass Scanner

Pass Scanner lets staff scan Apple Wallet and Google Wallet passes to view and manage privileges in real-time for controlled access environments.

Pass Scanner is a mobile application designed to allow staff to scan a pass, view all associated privileges, and consume them. It works on both iOS and Android devices, and while NFC scanning is planned for the future, the current version relies on camera-based barcode and QR code scanning. Pass Scanner is not intended for a public use, it was designed for controlled access environments such as events, lounges, or internal company facilities.

\
The application is strictly online. Every scan requires a network connection to ensure that pass verification and privilege consumption are always performed in real time. Offline operation is not supported, which eliminates the risk of duplicate usage and ensures that all privilege consumption is immediately visible to the backend system.

{% embed url="<https://www.youtube.com/watch?v=bzlGOpzjKfI>" %}

## Passes and Privileges

Pass Scanner works with wallet passes stored in Apple Wallet or Google Wallet. Each pass contains a unique identifier linked to one or more privileges. These privileges can be one-time use, multi-use with counters, time-bound, or conditional. Pass Scanner itself does not define privileges but displays them and allows operators to consume them according to the rules set in the backend. For a detailed explanation of privilege types, administrators can refer to [Privilege](/guides-animation/engage-and-animate/privilege-and-activation/privilege).

\
Once a pass is scanned, the app sends its identifier to the backend for verification. The backend validates the pass, checks its status, and returns the list of privileges.\
\
Operators can then consume privileges:

* One-time privileges are disabled after redemption.
* Multi-use privileges are decremented after each redemption.

{% hint style="warning" %}
Consuming a privilege is irreversible.

Pass Scanner does not show a confirmation prompt.

Pass Scanner does not use PINs or extra approvals.
{% endhint %}

<details>

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

* **Events**: staff scan a VIP ticket to check lounge access, drink vouchers, or fast-lane privileges.
* **Hospitality**: lounge teams verify room-linked benefits such as breakfast access or welcome drinks.
* **Corporate access**: reception staff scan employee or guest passes to validate site access rights.
* **Membership clubs**: front-desk staff check remaining entries, guest passes, or time-limited perks.

</details>

## Install Pass Scanner

Pass Scanner runs on **iOS** and **Android**.

The app is published on the Apple App Store and Google Play.

TestFlight (iOS) and APK distribution (Android) can still be used for internal testing, staged rollouts, or managed devices.

<details>

<summary><strong>iOS (App Store)</strong></summary>

**Requirements**

* Active internet connection

**Install**

1. Open the **App Store**.
2. Search for **The Wallet Crew - Scanner (**[**App store link**](https://apps.apple.com/app/the-wallet-crew-scanner/id6758636841)**)**.
3. Tap **Get** / **Install**.
4. Open Pass Scanner from the home screen.

</details>

<details>

<summary><strong>Android (APK)</strong></summary>

**Requirements**

* Active internet connection

**Install**

1. Get the APK download link from your administrator.
2. Tap the link to download the APK.
3. Open the downloaded file from Notifications or Downloads.
4. If prompted, allow your browser or file manager to **Install unknown apps**.
5. Open the APK again.
6. Tap **Install**.
7. Tap **Open**.

{% hint style="warning" %}
Only install Pass Scanner from an official store listing, or from a link provided by The Wallet Crew.

Never download the APK from third-party websites.
{% endhint %}

</details>

#### After installation

1. Open the app. You will see the scanner screen.
2. Scan the login QR code provided by your administrator. This QR code is created and managed from [Manage devices](/guides-scan/scan/pass-scanner/manage-devices).
3. Start scanning passes.

## Authentication and Operation

Pass Scanner uses **QR-code-based authentication**. An operator scans a login QR code, which the backend validates before issuing a session token. Once authenticated, the operator can scan passes and manage privileges. All operators have the same access level, with no roles or additional permissions required.

Because the app is online-only, reliable network connectivity is essential. Devices should be managed, monitored, and secured to maintain system integrity. Backend logs provide visibility into scan results, burn operations, and any errors, allowing administrators to track usage and troubleshoot issues efficiently.

## White-Label and Security

Pass Scanner is designed to support white-label deployment. Organizations can customize app names, icons, colors, logos, and splash screens without altering the app’s secure behavior or functionality. This makes it simple to integrate the app into an organization’s existing branding and operational workflows.

\
From a security perspective, Pass Scanner minimizes risk by keeping all sensitive logic on the backend. Burn operations are verified server-side to prevent fraud, and authentication tokens are short-lived. Devices should be treated as managed and controlled, ensuring that only authorized staff can scan passes and consume privileges.

## FAQ

<details>

<summary>Can Pass Scanner be used offline?</summary>

No. Pass Scanner is **online-only**.

Every scan requires a network connection.

</details>

<details>

<summary>How is Pass Scanner installed?</summary>

Install Pass Scanner on staff devices (iOS and Android).

Pass Scanner is not intended for public distribution.

Most teams install it from the Apple App Store and Google Play.

If an alternative install channel is needed (TestFlight or APK), contact The Wallet Crew.

</details>

<details>

<summary>What is the login protocol?</summary>

Pass Scanner uses **QR-code-based authentication**.

An operator scans a login QR code.

The backend validates it and issues a **session token**.

</details>

<details>

<summary>Does Pass Scanner support white-labeling?</summary>

Yes. You can customize the app name, icon, colors, logos, and splash screen.

Branding does not change the security model.

</details>

<details>

<summary>Is scanning a pass reversible?</summary>

Scanning a pass is **read-only**.

It fetches pass status and the current list of privileges.

What is **not reversible** is consuming a privilege.

Once consumed, it is recorded server-side immediately.

It cannot be undone from Pass Scanner.

</details>


# Manage devices

Manage the devices allowed to sign in to Pass Scanner, distribute their login QR codes securely, and revoke or rotate access when needed.

The Devices page controls which phones are allowed to connect to Pass Scanner. Each device entry represents one scanner installation and one login credential. This page is where administrators create new devices, share the connection QR code, and revoke or rotate access when a phone changes hands.

The device QR code should be treated like a password. Anyone with access to that QR code can sign in a device to Pass Scanner. Device management is therefore both an operational topic and a security topic.

{% hint style="warning" %}
The device QR code is a credential. It should only be shared through trusted channels and only with the staff member or supervisor responsible for that device.
{% endhint %}

<details>

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

* **Event operations:** each gate supervisor receives a dedicated device QR code for a managed phone.
* **Retail or lounge access:** each counter phone has its own device entry, which makes access easy to revoke without affecting the rest of the team.
* **Temporary staff:** a device can be enabled for a campaign or event day, then disabled immediately after the shift.
* **Lost or replaced phone:** the connection can be reset to invalidate the previous QR code and issue a new one.

</details>

## How device management works

Pass Scanner uses QR-code-based sign-in. When a device is created, The Wallet Crew generates a QR code linked to that device record. The phone scans that QR code from the Pass Scanner app to establish its connection.

Using one device entry per physical phone is the safest model. It keeps revocation precise, makes audits easier, and avoids sharing one credential across several operators. It also helps operations teams identify which phone should be disabled or reset when an incident occurs.

### Add a new device

Adding a device creates a new login credential for Pass Scanner. This should be done for each phone that will scan passes in production.

{% stepper %}
{% step %}

#### Create the device entry

From the Devices page, select **New** to create a device.
{% endstep %}

{% step %}

#### Enter the device details

Add a clear name. An optional description can be used to identify the location, team, or purpose of the phone. New devices are enabled by default.
{% endstep %}

{% step %}

#### Save and capture the QR code

Once the device is created, the connection QR code becomes available. That QR code is the credential used by the Pass Scanner app to sign in the phone.
{% endstep %}
{% endstepper %}

Using a naming convention helps keep the fleet readable. For example, a Brand can use a store code, gate number, or role such as `Paris-Flagship-Checkout-1` or `VIP-Gate-A`.

### Share the device QR code securely

The device QR code should be shared with care because it grants access to Pass Scanner. In many deployments, the safest approach is to display it locally to the operator during setup rather than sending it through broad internal channels.

If the QR code is forwarded by email, chat, or screenshot, access is no longer controlled by possession of the phone alone. That increases the risk of unauthorized sign-in. When in doubt, reset the connection and issue a new QR code.

The QR code can only be viewed when the device is created. This makes the initial setup moment important. It should be captured and transmitted through a trusted process.

### Disable, enable, or delete a device

Device status changes allow administrators to control who can sign in without recreating the whole fleet. The right action depends on whether access should be paused, restored later, or removed permanently.

**Disable a device** when access should stop temporarily. This is useful for seasonal operations, temporary staff, lost phones that may be recovered, or any short-term security doubt. A disabled device can be enabled again later.

**Enable a device** when a previously disabled phone is authorized to return to service.

**Delete a device** when it is no longer needed and should not come back, for example after a permanent decommissioning. If a device may return later, disabling is usually safer than deleting.

### Reset a device connection

Resetting the connection rotates the credential for an existing device. A new QR code is generated and the old one stops working immediately.

This action is useful when the QR code may have been exposed, when the phone is replaced, or when setup must be performed again under controlled conditions. Resetting the connection is often the fastest way to restore trust without deleting and recreating the device.

### Operational recommendations

Device management works best when each phone has its own clearly named record and each credential is treated as short-distribution, high-trust information. This keeps revocation targeted and avoids operational confusion during busy periods.

For most projects, the following practices reduce support load and security risk:

* Create one device per physical phone.
* Use names that identify the location or role clearly.
* Disable unused devices as soon as a shift, event, or campaign ends.
* Reset the connection immediately if a QR code was shared too broadly.
* Prefer disabling over deleting when the device may return to service.

## FAQ

<details>

<summary><strong>Should several phones share the same device?</strong></summary>

No. One device per phone is the recommended model. It keeps access control precise and makes investigation or revocation much easier.

</details>

<details>

<summary><strong>What happens after a connection reset?</strong></summary>

The previous QR code becomes invalid immediately. A new QR code replaces it for the same device record.

</details>

<details>

<summary><strong>When should a device be disabled instead of deleted?</strong></summary>

Disable a device when access should stop temporarily or when the phone may return later. Delete a device only when it is no longer needed at all.

</details>

<details>

<summary><strong>Why is the QR code considered sensitive?</strong></summary>

The QR code is the login credential for Pass Scanner. Anyone who receives it may be able to authenticate a device, so it should be handled with the same care as a password.

</details>

<details>

<summary><strong>What is the best response if a QR code was shared in an unsafe channel?</strong></summary>

Reset the connection immediately. This invalidates the previous QR code and restores control with a newly generated credential.

</details>


# Scanner

Select scanner hardware that reliably reads barcodes and QR codes from Apple Wallet and Google Wallet passes.

## Scan wallet passes with barcode and QR code readers

Barcode and QR code passes are made to be presented on a phone screen. The scan experience depends on the scanner hardware, its configuration, and on-site conditions.

Hardware constraints often drive the decision between barcode/QR scanning and NFC. A broader compatibility overview is available in [Hardware](/connectors/hardware).

<details>

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

* Retail loyalty: a 2D scanner reads a QR code from a phone at checkout.
* Event entry: handheld scanners read QR codes at the gate, in bursts.
* Gift card redemption: a counter scanner reads a barcode, then applies value.
* Pop-ups: a staff smartphone validates passes using a camera-based scanning app.

</details>

### Recommended scanner type for phone screens

2D imaging scanners (2D imagers) are typically the right choice for wallet projects. They capture the code as an image, which makes reading from screens reliable.

Laser scanners can work well on printed 1D barcodes. They often underperform on phone screens because reading depends on reflected light. Modern screens and protective glass tend to reduce that reflection.

{% hint style="info" %}
Most 2D imagers support many 1D and 2D symbologies. Support varies by model and license. Hardware specs should be checked against the barcode formats used in pass templates.
{% endhint %}

### 1D vs 2D codes (why it matters for scanners)

<figure><img src="/files/trWk27Z2ayHG7s3pYciy" alt="Comparison between a 1D barcode (linear bars) and a 2D barcode (matrix code such as QR)."><figcaption><p>1D codes are linear. 2D codes are matrix-based.</p></figcaption></figure>

#### 1D (linear) barcodes

1D barcodes are parallel bars, often with a human-readable number below. They usually carry short identifiers.

They can be fast to scan at distance. They also tend to be cheaper to support in hardware.

#### 2D (matrix) barcodes

2D barcodes store data in a grid. QR code and Data Matrix are common examples. They can store more data and are widely used for tickets.

They scan well at short range and in multiple orientations, which helps throughput in crowded environments.

### Practical selection checklist

Scanner selection should be validated early. It reduces rollout risk and avoids late read-rate issues.

Key checks that usually matter in production:

* Confirm “reads from **mobile screens**” is explicitly supported.
* Prefer **2D imagers** for mixed 1D/2D needs and screen reliability.
* Confirm supported symbologies match what is used (QR, Data Matrix, Code 128, PDF417, etc.).
* Test with iOS and Android devices, across low and high brightness.
* Test with common phone conditions: screen protector, cracked glass, and low-battery dimming.
* Validate throughput in realistic conditions (queue, scan distance, staff habits).

### FAQ

<details>

<summary><strong>Does barcode scanning require NFC-capable hardware?</strong></summary>

No. Barcode and QR code scanning uses optical reading (scanner or camera).

NFC is a different hardware and protocol layer. More context is available in [Hardware](/connectors/hardware).

</details>

<details>

<summary><strong>Can a phone screen be scanned with a 1D laser scanner?</strong></summary>

Sometimes, but it is not a reliable baseline for production. Many 1D laser scanners struggle on phone screens due to reflection and screen technologies.

2D imagers are the common default for wallet deployments because they are built to read from screens.

</details>

<details>

<summary><strong>Should QR code be preferred over a 1D barcode for wallet passes?</strong></summary>

QR codes are widely supported by 2D imagers and work well on screens.

The right choice depends on operational constraints and existing infrastructure. When 1D barcodes are required, using 2D imagers still keeps scanning reliable on phone screens.

</details>


# crew-check


# HOW TO CONFIGURE

The Wallet Crew documentation is organized around three main areas. Each section covers a distinct part of the setup and operations flow.

Before creating passes or connecting external systems, a number of parameters must be set at the platform level. The Configuration section covers everything needed to make The Wallet Crew operational for a brand: from the initial account setup to the visual design of Wallet templates, including the technical credentials required to issue passes through Apple Wallet and Google Wallet under the brand's own identity.

<table data-view="cards"><thead><tr><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h3>Platform</h3></td><td><a href="/files/ehV2YmdYDdxaCYAEV9JS">/files/ehV2YmdYDdxaCYAEV9JS</a></td><td><a href="/pages/ZlJuyLbDiH4h9cxJYtI3">/pages/ZlJuyLbDiH4h9cxJYtI3</a></td></tr><tr><td><h3>Wallet</h3></td><td><a href="/files/eo7TEtVZqQTRn7zwmtMb">/files/eo7TEtVZqQTRn7zwmtMb</a></td><td><a href="/pages/3hygUQfY4HjbR0PoBiO6">/pages/3hygUQfY4HjbR0PoBiO6</a></td></tr><tr><td><h3>Enrolment Form</h3></td><td><a href="/files/EuXA3EcgM6gLsYPShlvx">/files/EuXA3EcgM6gLsYPShlvx</a></td><td><a href="/pages/iPkpzqpCf0liHTb6cyU7">/pages/iPkpzqpCf0liHTb6cyU7</a></td></tr></tbody></table>

**Platform settings** are the starting point. This is where the tenant is initialized — general parameters such as the application title, supported languages, and the favicon displayed on hosted pages. User access and multi-factor authentication are configured here, as well as the API keys used to authenticate backend requests to The Wallet Crew APIs. Brands that want to host enrolment and download pages under their own domain will also find the custom domain configuration in this section.

**Wallet settings** cover the credentials that Apple and Google require to issue passes. Each platform has its own authentication mechanism: Apple Wallet relies on certificates and push notification identifiers managed through the Apple Developer account, while Google Wallet requires access to the Google Pay & Wallet Console and dedicated API credentials. Both must be configured before any pass can be created or distributed.

**Template configuration** defines the structure and appearance of the passes themselves — field layout, colors, images, and dynamic content via the DotLiquid templating engine. Templates can be translated into multiple languages and duplicated or imported across tenants.


# Enrolment Form

Hosted enrolment forms support secure pass creation and retrieval flows. This section covers customer identification, access control, and form behavior used before wallet delivery.

## Customer registration configuration

Customer registration captures identity before issuing a pass. Use it when a CRM or POS account must be created or updated first. It supports website enrolment and in-store QR-code registration.

### Sign-in options (`signinOptions`)

`signinOptions` controls how returning customers are detected and handled. It can check for an existing session or route to a mobile sign-in journey based on device detection.

### Complete options (`completeOptions`)

`completeOptions` is an ordered list of actions taken after successful registration. Each action has a `type`.

| Type             | What it does                                                                                                        |
| ---------------- | ------------------------------------------------------------------------------------------------------------------- |
| `AddToWallet`    | Presents Add to Wallet buttons. Supports `autoDownloadPass` and an optional post-download form.                     |
| `Redirect`       | Redirects to a fixed URI. It supports Liquid variables, such as `{{['id.y2.customerId']}}`, in the destination URL. |
| `RedirectToPass` | Redirects to a named pass-download layout for immediate pass download.                                              |
| `Reset`          | Resets the form after a configured delay in seconds. Use this for shared in-store kiosks.                           |

### Localize form text and consent wording

All customer-facing text on the enrolment form - field labels, instructions, and consent/opt-in copy - is stored in per-tenant localization files. Access them from **Settings** → **Enrolment** → **Localization files**.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/settings/enrolment/localization-files" class="button secondary" data-icon="angles-right">Open Localization files</a></p>

Most tenants have a `fields` locale file (`locales/fields`), which governs the enrolment form field labels and consent/opt-in text. Edit it inline from the Localization files screen, the same way pass template fields are translated (see [How to Translate a template](/configure/advanced-configuration/wallet/template-configuration/how-to-translate-a-template)).

Update the wording for every active language configured on the tenant. A change made in one locale file does not propagate to other languages automatically.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4>Enable Email check-in on Enrolment Forms</h4></td><td>Secure hosted enrolments flow, check existing customers by email, add optional verification, and reduce duplicate accounts before pass creation, reterieval, or wallet downolad across campaigns.</td><td><a href="/files/Acd9UnI83Z8OHH65LzU3">/files/Acd9UnI83Z8OHH65LzU3</a></td><td><a href="/pages/QbgmRSWuqATWBWZ5O04w">/pages/QbgmRSWuqATWBWZ5O04w</a></td></tr></tbody></table>

The Enrolment Form section covers the advanced configuration of the sign-up experience. When a customer submits their email address, TWC can automatically check whether they already exist in the system. If they do, an optional verification step — such as a one-time code or magic link — secures access before the pass is issued. If they don't, the form collects the remaining details and creates a new record. This prevents duplicate entries and keeps your customer database consistent, without requiring any additional development on your side.


# Enable Email Check-in on Enrolment Forms

Check if a customer already exists by email, then secure access with optional verification.

If you ever decide to stop using The Wallet Crew, you can do it anytime. This page explains how to migrate without breaking pass updates for customers.

This is also why we ask Brands to use their own Apple and Google Wallet accounts. It keeps you as the issuer of record. It also prevents vendor lock-in.

Your customer data is yours. You stay the data controller. In practice, your source of truth stays in your CRM and internal systems.

To switch providers, you export the operational pass identifiers from The Wallet Crew. You give them to your new provider so they can take over updates.

{% hint style="info" %}
If you’re considering leaving because of a blocker, tell us early. We can often fix it without requiring a migration.
{% endhint %}

Apple Wallet and Google Wallet do not behave the same. Apple passes fetch updates from a `webServiceURL`. Google passes are tied to a Google Wallet issuer account.

## What you need to plan (Apple vs Google)

### Apple Wallet

Apple passes installed on devices keep calling the `webServiceURL` embedded in the pass.

To move to a new provider, you need to:

1. Export each pass **serial number** and **authentication token**.
2. Update the `webServiceURL` to your new provider endpoint.
3. Trigger an update so devices download a pass version pointing to the new provider.

### Google Wallet

Google Wallet passes are tied to a **Google Wallet issuer account**.

You cannot "transfer" passes to a different issuer account. Your new provider must either:

* operate under the **same** issuer account, or
* re-issue passes under a new issuer account (new save links, new objects).

## Step-by-step

{% stepper %}
{% step %}

### Export pass data from The Wallet Crew

Open the passes list in the admin console:

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/passes/" class="button secondary" data-icon="chevrons-right">The Wallet Crew Administration Console - Pass List</a></p>

Export the full list.

Make sure the export includes, at minimum:

* Apple: **serial number** and **authentication token**
* Google: **resource ID** (or object ID)
* Your external identifiers (so the new provider can map passes back to customers)
  {% endstep %}

{% step %}

### Give the export to your new provider

Send the exported file to your new provider. They need it to attach to existing passes.

For Apple, they will typically import serial + auth token to be able to sign and serve updates.

For Google, they will typically use resource IDs to update the existing objects.
{% endstep %}

{% step %}

### Switch Apple passes to the new update endpoint

Agree on the new Apple Wallet web service endpoint with your new provider.

Then ask The Wallet Crew team to:

1. configure the target `webServiceURL` for your tenant, and
2. run a bulk "push update" so installed passes pick up the new URL.

{% hint style="warning" %}
If you switch the `webServiceURL` without a working endpoint on the new provider, Apple passes may stop updating.

Plan a short validation window and test on a small sample first.
{% endhint %}
{% endstep %}

{% step %}

### Validate the migration

Pick 2–3 test passes (Apple and Google).

Ask the new provider to:

* update a visible field (example: points balance, status, or event gate)
* confirm the update is visible on devices within a few minutes

For Apple, also confirm that updates still work after reinstalling the pass.
{% endstep %}
{% endstepper %}

## FAQ

<details>

<summary><strong>Do end-users need to reinstall their pass?</strong></summary>

Usually no.

If you switch Apple `webServiceURL` correctly, existing passes keep updating without reinstall.

For Google, if you keep the same issuer account and object IDs, users typically keep the same pass.

</details>

<details>

<summary><strong>Can we move Google Wallet passes to a different issuer account?</strong></summary>

Not in-place.

Google Wallet passes are tied to the issuer account. If the issuer changes, plan a re-issuance flow.

</details>

<details>

<summary><strong>What’s the minimum data we must export?</strong></summary>

For Apple, you need the serial number and authentication token.

For Google, you need the resource ID.

External identifiers are strongly recommended. They let the new provider keep pass-to-customer mapping.

</details>


# Platform

The Wallet Crew documentation is organized around four main areas. Each section covers a distinct part of the setup and operations flow.

The Platform section covers the foundational settings that apply across the entire account. These are the parameters to configure first — before creating passes, connecting systems, or inviting team members.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4>General</h4></td><td>Manage your tenants settings, team members, and core configuration from a single voice.</td><td><a href="/files/ZUoFTnoY83xrJzRzknMC">/files/ZUoFTnoY83xrJzRzknMC</a></td><td><a href="/pages/g9Fnj5ecOdErumGyeubK">/pages/g9Fnj5ecOdErumGyeubK</a></td></tr><tr><td><h4>User Access</h4></td><td>Invite team members, assign roles, and control who can view, edit or manage your platform.</td><td><a href="/files/DRl7DXdBdiH0akHVZHqe">/files/DRl7DXdBdiH0akHVZHqe</a></td><td><a href="/pages/dfeWugPHr92B7ziYKsUL">/pages/dfeWugPHr92B7ziYKsUL</a></td></tr><tr><td><h4>API Key</h4></td><td>Generate, scope and revoke API keys for production and staging environments securely.</td><td><a href="/files/8Lnp0SGK5xxVBwsFrdvZ">/files/8Lnp0SGK5xxVBwsFrdvZ</a></td><td><a href="/pages/z8ZCmjLonvGwOKBok0YG">/pages/z8ZCmjLonvGwOKBok0YG</a></td></tr><tr><td><h4>Custom Domain</h4></td><td>Connect your own domain, configure your CNAME record, and let TWC handle SSL automatically.</td><td><a href="/files/N9u59v8LiAfwq5vrWcmp">/files/N9u59v8LiAfwq5vrWcmp</a></td><td><a href="/pages/XW2egQ1dxnBa9J6LoOF8">/pages/XW2egQ1dxnBa9J6LoOF8</a></td></tr></tbody></table>

**General settings** define the basic identity of the account: the application title, the favicon displayed on hosted pages, and the languages available for enrolment and pass download pages. These settings are visible to end-users and should reflect the brand's identity from day one.

**User access** controls who can log into the back office and with what level of permissions. This is where the administrator account is created, team members are invited, and multi-factor authentication (MFA) is enabled. Keeping access well-defined from the start reduces security risks and avoids confusion when multiple people work on the same account.

**API keys** are required for any backend integration. Each key is scoped to the account and must be included in every API request sent to The Wallet Crew. Keys can be created, rotated, and revoked from this section. Anyone setting up a technical integration will need at least one active API key before making their first call.

**Custom domain** allows brands to replace The Wallet Crew's default hosted URLs with their own domain — for enrolment forms, pass download pages, and account-linked Wallet journeys. This is a branding decision as much as a technical one: end-users see the brand's domain throughout the experience, not a third-party URL.

These four settings are independent of each other and can be configured in any order. That said, completing General settings and User access first is recommended, as they affect how the rest of the platform behaves for the whole team.


# General

When your tenant has been created, you can start setting up The Wallet Crew.

Basic configuration allows you to define:

### Application Title

* **Title of the application:** This will be used as the title of the web page and for the name of the application when PWA is active. If no title is specified, the name of the tenant will be used.

### Favicon

* **Favicon:** The icon that will be used for The Wallet Crew web pages, which includes pages for creating or sharing cards with your customers.

![Favicon](/files/1EaFhqjNfJPs0kwyPgPP)

### Localizations

* **Localizations:** Specify the languages you wish to deploy. These languages will be available for translations on various The Wallet Crew landing pages used for registration or card download, as well as for information displayed on cards available in Wallets.

#### **Adding a Language**

* **To add a language:**
  1. Type the 2 ISO letters related to the language.
  2. Click on the “+” icon.

![Localizations](/files/Np05GTtvSNyPG8yjFQKi)

You can click on the icon next to the 2 ISO letters to choose the default language.

### Saving Changes

* Once all configurations are set, ensure to click the "Save" button at the top of the page to apply your changes.

This guide provides a basic overview of setting up your Wallet Crew tenant. For more advanced configurations and features, refer to The Wallet Crew advanced settings documentation.


# Webhooks

Receive real-time HTTP notifications for events in The Wallet Crew.

Webhooks allow systems to receive real-time HTTP notifications whenever an event occurs in The Wallet Crew. Webhook registration is self-serve through **Settings → General → Webhooks** in the admin console. No API call is required to create or manage webhooks.

## Manage webhooks from the console

Open **Settings → General → Webhooks**. The list shows all registered webhooks, including **Description**, **Endpoint**, **Events**, and **Enabled** status.

To create or edit a webhook, open its edit form. The form contains the following fields:

* **ID** — Auto-generated and read-only. Use this value to reference the webhook through the API.
* **Secret** — The HMAC signing key used to verify deliveries. A show/hide toggle controls visibility. Store this value server-side and never expose it in client code.
* **Enabled** — Pauses or resumes delivery without deleting the webhook.
* **Description** — A label used for reference.
* **Endpoint** — The HTTPS URL that receives `POST` requests.
* **Events** — One or more event subscriptions. Use **Add event** and **Remove event** to manage the list.

## Event filter syntax

Each **Events** entry is a string. Three forms are supported:

| Syntax         | Meaning                                         |
| -------------- | ----------------------------------------------- |
| `*`            | Subscribe to all events.                        |
| `Pass:*`       | Subscribe to all events in the `Pass` category. |
| `Pass:Created` | Subscribe to one specific event.                |

Wildcards and explicit events can be combined in the same webhook. For example:

* `["Customer:*", "Pass:Created"]`
* `["Pass:*", "Redirect:Redirected"]`

## Signature validation

Every delivery includes the `x-neostore-signature` header. Validate it server-side with the webhook **Secret**. See the [Webhooks developer guide](https://docs.thewalletcrew.io/developers-guides/integration-guides/webhooks) for the full validation pattern and event payload reference.

{% hint style="warning" %}
Always validate `x-neostore-signature` on every incoming request. Do not rely solely on network IP allowlists.
{% endhint %}


# User Access

Create an admin account and manage back-office users.

Access to the admin console follows two paths. The first path is used during onboarding: a person creates an account, then The Wallet Crew grants access to the tenant. The second path is used after onboarding: a tenant administrator adds and manages other back-office users directly from the admin console.

{% hint style="info" %}
If sign-in works but no tenant appears, access has not been granted yet.
{% endhint %}

### Create an admin account

For first access to a tenant, start by creating a personal account in the admin portal. This creates the login account, but it does not grant tenant access on its own.

{% stepper %}
{% step %}

#### Open the admin portal

Open <https://admin.thewalletcrew.io/>. This is where you sign up and sign in to the administration console.
{% endstep %}

{% step %}

#### Sign up

Start the sign-up flow and choose the preferred method. Once the account is created, The Wallet Crew can grant the first access to the tenant.

<figure><img src="/files/W5PneynD9sgGPqcOG2co" alt="Admin portal sign-up screen with Google, Microsoft, and email sign-in options"><figcaption><p>Create the first back-office account from the admin portal sign-up page.</p></figcaption></figure>
{% endstep %}
{% endstepper %}

{% hint style="info" %}
Use your work email. It makes access assignment faster.
{% endhint %}

### Get access to a tenant

For the first administrator of a tenant, access is usually granted by The Wallet Crew during onboarding. Once a tenant already has an administrator, that administrator can grant access to other users without going through support.

<details>

<summary>Real-world examples</summary>

* A brand contact creates an account during onboarding. The Wallet Crew grants the first access to the tenant.
* A tenant administrator later adds colleagues from the **Users** tab.

</details>

#### Manage back-office users

Once a tenant administrator has access, back-office users can be managed from **Settings → Access control → Users**. The **Roles** tab next to it is used to review the available roles.

The **Users** tab displays a table with **Email**, **Name**, **Role**, **Status**, and **Last login**. Active users appear with an **Active** badge in the **Status** column. The **+ Add new** action opens the user form, and each row menu provides **Edit** and **Delete** actions.

<figure><img src="/files/OpJmUAdl1rKo0P7LVgWU" alt="Users list in Access control showing email, name, role, status, and last login"><figcaption><p>The Users page centralizes user creation, role assignment, and access review.</p></figcaption></figure>

{% stepper %}
{% step %}

#### Open Users

Open **Settings → Access control → Users**.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/access/users-and-roles/users" class="button secondary" data-icon="chevrons-right">Open Users in the admin console</a></p>
{% endstep %}

{% step %}

#### Add a new user

Click **+ Add new**.
{% endstep %}

{% step %}

#### Fill the user details

Fill **Email**, **Name**, and **Role**, then click **Save** in the top-right corner.

The form also shows a read-only **User ID** generated by the system.
{% endstep %}
{% endstepper %}

To edit a user, open the **...** menu on the user row, click **Edit**, update the fields, then click **Save**.

To delete a user, open the **...** menu and click **Delete**. This removes access to the tenant, but does not erase the person’s login account.

### FAQ

<details>

<summary>I can sign in, but I see no tenant. What’s happening?</summary>

The account exists, but it has not been granted access to any tenant yet. For first access, contact The Wallet Crew during onboarding. If the tenant already has an administrator, that administrator can grant access from [Manage back-office users](#manage-back-office-users).

</details>

<details>

<summary>Can a tenant administrator add another user?</summary>

Yes. A tenant administrator can open **Settings → Access control → Users**, click **+ Add new**, fill the user details, and save.

</details>

<details>

<summary>I can access a tenant, but I can’t see Settings. Why?</summary>

The account has access to the tenant, but not with administrator rights. Ask a tenant administrator to review the assigned role.

</details>

<details>

<summary>Does signing up automatically create a tenant?</summary>

No. Signing up only creates the account. Access to a tenant is granted separately.

</details>

<details>

<summary>Can I access multiple tenants with the same account?</summary>

Yes. The same account can be granted access to multiple tenants. The assigned role can differ from one tenant to another.

</details>

<details>

<summary>Should I use my work email or a personal email?</summary>

Use a work email whenever possible. It makes onboarding and access management easier.

</details>

<details>

<summary>I picked the wrong sign-in method (Google vs Microsoft vs email). Can I change it later?</summary>

Avoid signing up again with a different method, because it can create a second identity. If you must switch methods, contact The Wallet Crew support so access can be reassigned safely.

</details>


# API Keys & Secrets

Manage the three types of credentials used to authenticate API calls, SDK integrations, and connector connections.

API keys authenticate server-to-server calls to The Wallet Crew APIs. API keys are tenant-scoped. A key only works for a single tenant. Integrations spanning multiple tenants require one key per tenant.

API keys can also be scope-restricted. Least privilege reduces risk and limits blast radius.

<details>

<summary>Real-world examples</summary>

* A Brand CRM job updates loyalty points nightly, then triggers pass updates.
* An integration middleware issues new passes after an e-commerce checkout event.
* A data pipeline fetches pass installation status and sends it to analytics.

</details>

## Before you start

* An admin account with access to **Settings** is required.
* The intended usage and owning system are identified (service, job, connector).
* The minimum required scopes are listed. Each API endpoint documents its required scopes, and the admin console lists the available scopes at key creation time.

{% hint style="warning" %}
Never ship an API key in a mobile app or in front-end JavaScript. Treat it like a password.
{% endhint %}

### Create an API key

{% stepper %}
{% step %}

#### Open API Keys

1. Sign in to the admin console.
2. Go to **Settings → Security → API Keys**.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/settings/security/apiKeys" class="button secondary" data-icon="chevrons-right">The Wallet Crew - API Keys</a></p>
{% endstep %}

{% step %}

#### Add a new key

1. Click **Add new**.
2. Set a clear name.
   * Example: `crm-sync-prod` or `nightly-pass-update`.
3. Select the scopes you need.
4. Click **Save**.
   {% endstep %}

{% step %}

#### Copy and store the key

The key value is only displayed once, right after creation. After the dialog is closed, the value cannot be retrieved.

The key should be stored in a secret manager. Read access should be limited to the smallest set of services and operators needed to run the integration.
{% endstep %}
{% endstepper %}

### Use the key in API requests

Send the key in the `X-API-KEY` header.

Example header:

`X-API-KEY: <your_api_key>`

The full endpoint list and request/response formats are available in the [API reference](https://docs.thewalletcrew.io/api-reference/).

#### Validate access quickly

Authentication and authorization failures look similar, but mean different fixes. A quick validation flow helps isolate the issue early.

Run a low-impact `GET` request that matches the selected scopes. A `401 Unauthorized` response typically indicates a missing, invalid, or revoked key. A `403 Forbidden` response typically indicates a valid key with insufficient scopes.

### Manage, rotate, revoke

* **Rotate** keys regularly.
  * Create a new key.
  * Deploy it to your services.
  * Revoke the old key after a short overlap.
* **Revoke** keys immediately if they leak.
* Keep separate keys per environment and integration.

### Troubleshooting

* **401 Unauthorized**
  * Missing or invalid `X-API-KEY` header.
  * Key was revoked.
* **403 Forbidden**
  * Key is valid but missing required scope.

### FAQ

<details>

<summary>Can one API key be used across multiple tenants?</summary>

No. API keys are tenant-scoped. Each tenant requires its own key, even when the same integration runs in multiple tenants.

</details>

<details>

<summary>Can an API key be retrieved later if it was not copied?</summary>

API keys are meant to be shown once at creation time. If the value is lost, the safest path is to revoke the old key and create a new one.

</details>

<details>

<summary>What is the best way to name API keys?</summary>

A name should identify the owning system and environment. Names like `crm-sync-prod` or `data-export-staging` make rotation and incident response much faster.

</details>

<details>

<summary>How to rotate keys without downtime?</summary>

Create a new key and deploy it first. Keep both keys active during a short overlap. Revoke the old key once logs confirm the new key is used everywhere.

</details>

<details>

<summary>Where is the scope reference?</summary>

Each API endpoint documents the required scopes in its own documentation.

The admin console remains the place where available scopes can be reviewed and selected when creating or editing a key.

</details>

## General secrets

General secrets are named credentials used by SDK integrations. Create a General secret when an SDK integration requires a shared secret that is not an API key.

### Create a General secret

1. Go to **Settings → Access Control → API Keys & Secrets**.
2. Open the **General secrets** tab.
3. Click **Add new** and give the secret a clear name.
4. Copy the value immediately. It is only shown once.

Store the value in the integration's secret manager. Treat it with the same care as an API key.

## App secrets

App secrets are credentials that connectors use to authenticate against external systems. Examples include passwords and access tokens for a CRM, POS, or marketing platform.

Most connectors manage App secrets through their own setup UI. Direct edits in this tab are rarely needed. The connector configuration flow handles them.

### View or update an App secret manually

1. Go to **Settings → Access Control → API Keys & Secrets**.
2. Open the **App secrets** tab.
3. Select the secret to edit.

{% hint style="info" %}
When setting up a connector, use its configuration UI rather than editing App secrets directly. The connector UI guides the setup and validates the credentials.
{% endhint %}


# Custom Domain

Use a brand-owned domain for hosted The Wallet Crew pages such as enrolment, pass download, and account-linked wallet journeys.

A custom domain aligns hosted The Wallet Crew pages with the Brand identity. It also reduces phishing risk and improves trust when customers open enrolment or pass download journeys.

By default, The Wallet Crew serves hosted pages on a The Wallet Crew domain such as `https://app.neostore.cloud/<tenantId>/<layout>`. A custom domain replaces that public entry point with a Brand-owned domain such as `https://wallet.example.com`.

<details>

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

* A retailer uses `wallet.brand.com` for loyalty enrolment and card retrieval.
* An event organizer uses `tickets.brand.com` for post-purchase wallet ticket download.
* A Brand uses `registration.brand.com` to keep the web journey aligned with its email sender identity.

</details>

## Why use a custom domain

The main goal is trust. A branded URL is easier to recognize than a shared platform domain. This usually improves conversion on sensitive flows such as enrolment, sign-in, and pass download.

It also improves security posture. A dedicated subdomain makes spoofing easier to detect and keeps wallet-related traffic isolated from the main website.

### Before starting

Choose the public domain that will host the journey. A dedicated subdomain is recommended, for example `wallet.example.com` or `registration.example.com`.

The Brand also needs access to its DNS zone. All DNS changes are made there.

{% hint style="info" %}
This page covers the hosted web domain only.

Email sender domains are configured separately. For email delivery, see [Email provider](broken://spaces/WLc8AHXW4tdrAXUBfrYF/pages/b1G2ZdAPKRiFTIkPcNH0) and [SendGrid](broken://spaces/WLc8AHXW4tdrAXUBfrYF/pages/OgPzPDbsw4y607vXzPEM).
{% endhint %}

### How the setup works

Custom domains for hosted The Wallet Crew pages are handled through Cloudflare. The Wallet Crew prepares the Cloudflare-side configuration and provides the exact DNS records to publish. The Brand adds those records in its DNS provider.

After the first validation succeeds, extra records can be required for domain ownership checks and certificate issuance. The Wallet Crew manages the hosted certificate lifecycle through Cloudflare once the DNS validation is complete.

### Configure the custom domain

{% stepper %}
{% step %}

#### Select the public domain

Pick the domain or subdomain that will be exposed to customers.

Examples:

* `wallet.example.com`
* `registration.example.com`
* `tickets.example.com`

In most cases, a dedicated subdomain is the safest option. It avoids conflicts with an existing website and keeps wallet traffic isolated.
{% endstep %}

{% step %}

#### Request activation from The Wallet Crew

Share the chosen domain with The Wallet Crew.

At this stage, The Wallet Crew prepares the hosted configuration and returns the DNS records required for validation and routing.
{% endstep %}

{% step %}

#### Publish the DNS records

Add the records exactly as provided by The Wallet Crew in the Brand DNS zone.

The first set usually includes:

* one routing record so the domain points to The Wallet Crew hosted pages
* one or more TXT records for domain ownership or certificate validation

The exact names and values are tenant-specific. They should not be guessed or reused from another environment.
{% endstep %}

{% step %}

#### Complete the validation round

Once the first records are visible in DNS, The Wallet Crew validates the domain.

If additional records are required, The Wallet Crew shares them. Add those records, then wait for the final validation to complete.
{% endstep %}

{% step %}

#### Test the journey end to end

Before go-live, open the final URL and validate the full journey:

* the page resolves on the custom domain
* HTTPS is valid
* the intended layout loads correctly
* enrolment, sign-in, or pass download flows still work as expected

If the custom domain is used with social sign-in, also update the allowed origins or callback configuration in the identity provider.
{% endstep %}
{% endstepper %}

### Example DNS records

The exact records vary by tenant and by infrastructure state. The example below is anonymized and shows the typical pattern only.

| Type  | Hostname                                      | Value                                                            | Purpose                                     |
| ----- | --------------------------------------------- | ---------------------------------------------------------------- | ------------------------------------------- |
| CNAME | registration.example.com                      | app.neostore.cloud                                               | Routes customer traffic to the hosted pages |
| TXT   | asuid.registration.example.com                | 621ECF9549EAE65BA089A426C8142E089EF4C6916FB9AB9F21C111F30D85E816 | Domain ownership validation                 |
| TXT   | \_acme-challenge.registration.example.com     | 7xLnjbponxeyiXkNsdIdrheyHHGouoFmfOXVvO9OAf8                      | Certificate validation                      |
| TXT   | \_cf-custom-hostname.registration.example.com | cdea2f9a-2a68-48ed-a83d-88403213a690                             | Additional custom hostname validation       |

### Validate before go-live

Use this checklist before exposing the domain publicly:

* DNS resolves to the expected target.
* HTTPS is active on the final URL.
* The hosted page loads with the expected branding and language.
* Any linked identity provider has been updated with the new domain.
* Internal teams use the custom domain in campaigns, QR codes, and support scripts.

### Common pitfalls

Most issues come from DNS or from other systems still pointing to the old domain.

* **Using the root domain instead of a dedicated subdomain** can create conflicts with the main website.
* **Publishing only the CNAME** is usually not enough. Validation TXT records are often required too.
* **Testing too early** can produce false negatives while DNS is still propagating.
* **Forgetting OAuth allowlists** can break Google, Apple, or Facebook sign-in on the new domain.
* **Mixing web domain and email sender domain setup** causes confusion. These are related branding choices, but separate technical configurations.

## FAQ

<details>

<summary><strong>Does a custom domain need to be a subdomain?</strong></summary>

No. A subdomain is strongly recommended to enfore brand authority.

It is easier to isolate, safer to operate, and less likely to conflict with an existing website or mail setup.

</details>

<details>

<summary><strong>Does the Brand need to provide its own SSL certificate?</strong></summary>

No.

The Brand manages the DNS records. The Wallet Crew manages the hosted certificate lifecycle after domain validation succeeds.

</details>

<details>

<summary><strong>Why can several TXT records be required?</strong></summary>

Different platform components can require different validation steps.

One record can prove domain ownership. Another can validate certificate issuance. A third can validate the custom hostname configuration.

</details>

<details>

<summary><strong>Can the Brand use Cloudflare Proxied DNS records?</strong></summary>

Yes.

The Wallet Crew supports Cloudflare **Proxied** mode, often called the orange-cloud proxy or orange-to-orange proxy. This allows the Brand to keep its own Cloudflare security, routing, and traffic rules in front of the hosted The Wallet Crew pages, on top of the security controls already managed by The Wallet Crew.

</details>

<details>

<summary><strong>Can the same domain also be used for email sending?</strong></summary>

The same brand namespace can be reused, but web hosting and email sending are separate setups.

For example, a Brand can use `registration.example.com` for hosted pages and `no-reply@registration.example.com` for transactional emails. The DNS records and validation process remain different.

</details>

<details>

<summary><strong>How long does the setup take?</strong></summary>

The timing mostly depends on DNS propagation and how quickly the required records are added.

The practical sequence is simple: receive the records, publish them, wait for validation, then run an end-to-end test.

</details>

<details>

<summary><strong>What else must be updated after switching to a custom domain?</strong></summary>

Any system that validates the public origin should be reviewed.

Common examples include social sign-in providers, redirect allowlists, QR code campaigns, email templates, and support documentation that still references the default The Wallet Crew domain.

</details>

<details>

<summary><strong>What happens if the selected subdomain already points somewhere else?</strong></summary>

That subdomain cannot point to two different targets at the same time.

If it is already used by another service, either move that service first or choose another dedicated subdomain for The Wallet Crew.

</details>


# Data & Integrations

Manage wallet programme reference data, including store and venue locations for geolocated notifications.

## Data & Integrations

Data & Integrations manages reference datasets used across wallet programmes.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4>Stores</h4></td><td>Manage physical locations for geolocated wallet pass notifications.</td><td></td><td><a href="/pages/9LaP8klliz6qm3uJ8ozK">/pages/9LaP8klliz6qm3uJ8ozK</a></td></tr></tbody></table>

**Stores** is a registry of physical locations, including retail stores, venues, and pop-ups. Each record contains a name, stable ID, and GPS coordinates. The Wallet Crew uses these coordinates for wallet pass location triggers and nearby messages.


# Stores

Manage physical store and venue locations for geolocated Apple Wallet and Google Wallet pass notifications.

## Manage stores for geolocated wallet pass notifications

Stores is the physical location registry for a wallet programme. It supports retail stores, venues, pop-ups, and other address-based sites.

The Wallet Crew embeds configured locations in wallet passes. A phone can then surface a contextual message when a customer is nearby.

{% hint style="info" %}
Stores are a prerequisite for geolocated notifications. At least one store must exist and be geocoded before location triggers can be configured on a pass template.

Configure geolocated notifications on the pass template after geocoding a store.
{% endhint %}

<details>

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

* A retailer can add a customer's preferred store to a loyalty pass.
* An event organiser can add a venue to an event ticket.
* A brand can add campaign pop-up locations to a wallet pass.

</details>

### Store location fields

| Field                    | Description                                                                                                                             |
| ------------------------ | --------------------------------------------------------------------------------------------------------------------------------------- |
| **ID**                   | A unique identifier for this location. Read-only after creation. Matched to customer data, such as a home store code from a POS or CRM. |
| **Store name**           | A human-readable label for internal management. Not shown to end-users.                                                                 |
| **Address**              | Street address. Used to geocode coordinates automatically.                                                                              |
| **Latitude / Longitude** | GPS coordinates. Populated automatically with **Find**, or entered manually.                                                            |

### Create and geocode a store

Create a store record before configuring a location trigger. Use a stable ID so the record can be matched with source data.

{% stepper %}
{% step %}
**Go to Data & Integrations → Stores**

Open the Stores page from the left navigation.
{% endstep %}

{% step %}
**Click Add**

The edit form opens.
{% endstep %}

{% step %}
**Fill in the ID and Store name**

Use a stable ID from the source system, such as a POS store code or CRM location ID. The ID cannot be changed after creation.
{% endstep %}

{% step %}
**Enter the address and geocode it**

Enter the address in **Address**, then click **Find**. The platform resolves GPS coordinates and positions a map pin. Review the pin position before saving.

If the resolved location is incorrect, adjust latitude and longitude manually. This can occur with large venues.
{% endstep %}

{% step %}
**Save**

Click **Save**. The store is now available for geolocation configuration.
{% endstep %}
{% endstepper %}

{% hint style="warning" %}
The **ID** is permanent. Use a stable, recognisable value from existing systems. Pass templates and Liquid logic reference this ID, for example, to assign a customer's home store.
{% endhint %}

### Import store locations in bulk

Use **Import** for large location lists. Use **Export** first to download a CSV template in the expected format.

### Edit or delete a store location

Click a row to edit its name, address, or coordinates. Use **Delete** to remove a store.

{% hint style="info" %}
Deleting a store removes it from future location calculations. Issued passes keep its coordinates until their next update.
{% endhint %}

When a store closes permanently, also delete its associated [redirect or QR code](/guides-enrolment/enrolment/enrolment-form/redirect) to prevent customers from scanning a code that no longer leads to an active enrolment journey.

### Geolocation limits for wallet passes

Apple Wallet and Google Wallet impose the following geolocation limits:

| Limit                         | Value |
| ----------------------------- | ----- |
| Maximum coordinates per pass  | 10    |
| Maximum radius per coordinate | 300 m |

The Wallet Crew selects stores to embed in each pass, based on the configuration. Retail programmes often embed a customer's home store and the nine closest locations.

### Frequently asked questions about stores and geolocation

<details>

<summary><strong>Can Stores be used for event venues?</strong></summary>

Yes. Any address-based location can be a store record. This includes stadiums, concert halls, conference centres, and pop-up sites. The registry is named “Stores,” but its records are not limited to retail locations.

</details>

<details>

<summary><strong>What happens when a store address changes?</strong></summary>

Changing an address and re-geocoding updates its registry coordinates. The new coordinates apply with the next pass update. Issued passes keep previous coordinates until then.

</details>

<details>

<summary><strong>Are coordinates required for every store?</strong></summary>

Only stores with latitude and longitude can be embedded in a pass. Records without coordinates remain valid but cannot trigger geolocation.

</details>


# Wallet

The Wallet section covers everything related to how passes are configured, designed, secured, and migrated. These settings are brand-specific — each one directly affects what end-users see and how passes behave on Apple Wallet and Google Wallet.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4>Apple &#x26; Google Wallet</h4></td><td>Connect your Apple Developer accound and Google Pay &#x26; Wallet Console to TWC.</td><td><a href="/files/ZUoFTnoY83xrJzRzknMC">/files/ZUoFTnoY83xrJzRzknMC</a></td><td><a href="/pages/oGyeqr2714g6XfR58VOE">/pages/oGyeqr2714g6XfR58VOE</a></td></tr><tr><td><h4>Template Config</h4></td><td>Create and customize your wallet pass templates : colors, logos, field layout, muti-language support.</td><td><a href="/files/DRl7DXdBdiH0akHVZHqe">/files/DRl7DXdBdiH0akHVZHqe</a></td><td><a href="/pages/9y0bkRWFXOyn989tjlPL">/pages/9y0bkRWFXOyn989tjlPL</a></td></tr><tr><td><h4>Wallet Cards Security</h4></td><td>GDPR and CCPA compliant, EU data residency, end-to-end encryption, strict tenant isolation.</td><td><a href="/files/8Lnp0SGK5xxVBwsFrdvZ">/files/8Lnp0SGK5xxVBwsFrdvZ</a></td><td><a href="/pages/4OjceSMZvirhikc0vL5e">/pages/4OjceSMZvirhikc0vL5e</a></td></tr><tr><td><h4>Import &#x26; Export</h4></td><td>Migrate active passes from another provider, update pass data via flat files or export passes to a new provider.</td><td><a href="/files/N9u59v8LiAfwq5vrWcmp">/files/N9u59v8LiAfwq5vrWcmp</a></td><td><a href="/pages/yyGb3SdHQ1hoVZAtIqCV">/pages/yyGb3SdHQ1hoVZAtIqCV</a></td></tr></tbody></table>

**Apple & Google Wallet** credentials define which entity issues passes on each platform. Rather than using shared or platform-default identities, TWC requires brands to connect their own Apple Developer account and Google Pay & Wallet Console. This ensures passes are distributed under the brand's name, with full control over certificates, push notification tokens, and API credentials. These credentials are a prerequisite for any pass issuance.

**Template configuration** is where the visual and structural identity of each pass type is defined. Templates control colors, logos, images, field labels and values, additional information, and links — for both Apple Wallet and Google Wallet. Dynamic content is handled through Liquid (DotLiquid), which allows field values to adapt per-pass without developer intervention. Templates can also be translated into multiple languages, with individual field translation or bulk export and import via Excel.

**Wallet Card Security** documents the security and compliance posture of the platform. Passes and associated personal data are stored exclusively in the European Union, encrypted at rest and in transit, and isolated per tenant. The platform is GDPR and CCPA compliant. Distribution links are cryptographically signed to prevent tampering. This section is the primary reference for security questionnaires and compliance reviews.

**Import & Export** covers scenarios where passes need to move — either into or out of The Wallet Crew. Existing passes from another provider can be migrated to TWC without requiring end-users to reinstall anything. Pass data can also be updated in bulk via flat files uploaded through SFTP. When switching to a new provider, TWC supports exporting passes with the constraints specific to each platform.

These four areas are independent but work together. Completing the Apple & Google Wallet credentials first is the recommended starting point — without them, no pass can be issued regardless of how templates or security settings are configured.


# Apple & Google Wallet

Configure Apple Wallet and Google Wallet securely, with brand-owned credentials for compliance.

The Wallet Crew generates passes for Apple Wallet and Google Wallet on behalf of Brand. Apple and Google enforce strict issuer identity, signing, and data-handling rules. This setup is critical for compliance and security. Brand must use Brand-owned Apple and Google issuer accounts and credentials.

Brand sets up and controls the accounts and credentials needed to issue passes (certificates, keys, issuer IDs, and approvals). The Wallet Crew uses Brand-provided values to sign and manage passes securely. This keeps Brand as the issuer of record and reduces credential risk. The Wallet Crew acts as the technical provider.

In practice, Brand Legal & IT teams manage the “issuer side” configuration. This includes account ownership, issuer identifiers, signing credentials, and provider approvals. Brand can rotate or revoke credentials at any time. The Wallet Crew should not be the long-term owner of issuer credentials.

{% hint style="warning" %}
This configuration keeps Brand in control of issuer identity and pass data. It also increases security by avoiding third-party ownership of signing keys and provider accounts, and by enabling Brand-managed rotation and revocation.
{% endhint %}

Brand security teams can review the platform security model in [Wallet card security](/configure/advanced-configuration/wallet/wallet-card-security).

### What happens during the onboarding process

* Brand completes the required Apple and Google setup under Brand accounts.
* Brand shares the required identifiers and credentials in the admin console.
* The Wallet Crew verifies the setup matches Apple and Google requirements.
* The Wallet Crew confirms readiness for pass generation and testing.

### More information

Use the platform-specific setup guides below

* Apple: create and manage certificates and push keys : [Apple Wallet certificates](/configure/advanced-configuration/wallet/apple-and-google-wallet/apple-wallet-certificates)
* Google: set up the issuer account and required credentials : [Google Wallet account](/configure/advanced-configuration/wallet/apple-and-google-wallet/google-wallet-account)

### FAQ

<details>

<summary><strong>Can a brand go live with only Apple Wallet or only Google Wallet?</strong></summary>

**No**. Brand needs to configure both Apple Wallet and Google Wallet before going live, so the program covers both iOS and Android users from day one.

</details>

<details>

<summary><strong>Can The Wallet Crew configure Apple/Google for a brand (delegated access)?</strong></summary>

**Yes**. Brand can grants temporary admin access in the provider portals, and delegate The Wallet Crew to do the configuration and removes admin access after validation. Brand remains the owner of the accounts and credentials.

</details>

<details>

<summary><strong>How long does setup take?</strong></summary>

It depends on organization size and whether Brand already owns Apple and Google accounts. Configuration takes around **15 minutes to 1 hour** per wallet provider.

</details>

<details>

<summary><strong>Can a brand rotate or revoke credentials? What happens to existing passes?</strong></summary>

**Yes**. Brand can rotate or revoke credentials at any time. If credentials are revoked, issuance and updates can stop until they are replaced, and installed passes may stop updating.

</details>

<details>

<summary><strong>Should Brand configure both staging and production?</strong></summary>

**No**. Brand can configure only one environment to start. The Wallet Crew can replicate configuration changes on demand.

</details>

<details>

<summary><strong>Does Brand need all information before starting the project?</strong></summary>

**No**. The Wallet Crew can provide test credentials to configure and set up the platform while the Brand team completes the configuration.

These credentials **can’t be used in production**. They are for testing only.

</details>


# Apple Wallet certificates

Configure your Apple Developer account to distribute digital wallet passes through The Wallet Crew platform. This guide covers certificate creation, push notification setup, and credential management

To issue Apple Wallet passes that display your company branding and receive real-time updates, you need to establish certificates and push notification credentials through the Apple Developer Program.

<figure><img src="/files/rwMoY59zEoQMMEnqGyn3" alt="The brand requests a Pass Type Certificate and an APNs key from Apple and delegates The Wallet Crew to issue the passes."><figcaption></figcaption></figure>

Want the “why” before the “how”? Start with [Apple & Google wallet](/configure/advanced-configuration/wallet/apple-and-google-wallet).

## Before you begin

### What you'll accomplish

* Create a Pass Type ID that identifies your organization as the pass issuer
* Generate and configure certificates that sign your wallet passes
* Set up Apple Push Notification service (APNs) for real-time pass updates
* Connect your Apple Developer account credentials to The Wallet Crew platform

### Prerequisites

* Active Apple Developer Program membership ($99/year for organizations)
* Administrator access to your Apple Developer account
* Authority to create certificates and authentication keys
* Access to The Wallet Crew admin console

### Apple Developer Program enrollment requirements

Before beginning this configuration, ensure your organization has enrolled in the Apple Developer Program as an **Organization** (not as an individual). This enrollment requires:

* **D-U-N-S Number** from Dun & Bradstreet for business verification. Apple usually sends it by email with the subject `Your D-U-N-S Number is enclosed.` from `Apple Developer <developer@email.apple.com>`
* **Work email address** linked to your company's domain (avoid personal Gmail/Yahoo accounts)
* **Publicly accessible website** reflecting your company's legal identity
* **Legal binding authority** as an owner, executive, or authorized employee to sign Apple's agreements

If you haven't enrolled yet, visit the Apple Developer Program enrollment page to begin the process. Enrollment as an organization (rather than individual) ensures your company name appears on wallet passes and enables multi-user account management.

<p align="center"><a href="https://developer.apple.com/programs/enroll/" class="button secondary" data-icon="chevrons-right">Apple Developer Program enrollment page</a></p>

## Kickoff

### Choose a setup path

* **Option 1 — Account delegation:** Grant The Wallet Crew administrator access to configure the integration. This is the fastest option.
* **Option 2 — Self-configuration:** Manage the complete setup within the organization. This maintains strict access control and requires familiarity with Apple Developer.

Both options provide the same functionality. Account delegation reduces the implementation workload. Self-configuration retains complete internal control.

### Option 1 — account delegation

This approach allows The Wallet Crew team to handle all technical configuration while you retain ownership of your Apple Developer account. You'll grant temporary administrator access, and we'll configure certificates, keys, and identifiers according to Apple's best practices.

#### Grant Administrator Access

Navigate to App Store Connect Users and sign in with your Apple Developer account credentials.

<p align="center"><a href="https://appstoreconnect.apple.com/access/users" class="button secondary" data-icon="chevrons-right">Apple Store Connect User</a></p>

Click the **Add (+)** button to invite a new user. Enter `contact@neostore.cloud` as the email address and assign the **Admin** role. This permission level allows The Wallet Crew team to create Pass Type IDs, generate certificates, configure push notification keys, and complete all necessary setup steps.

<div data-with-frame="true"><figure><img src="/files/a4996fb1f2ba3143c032bdb1558ac91faa969801" alt="App Store Connect users page showing how to invite a new admin user" width="375"><figcaption><p>App Store Connect users page showing how to invite a new admin user</p></figcaption></figure></div>

The Wallet Crew team will receive an invitation notification and will proceed with Pass Type ID creation, certificate generation, and APNs configuration. We'll notify you when setup is complete and provide documentation of all created resources. You can revoke this administrator access after confirming that wallet pass issuance and updates are working correctly.

**What happens next:** After you grant access, we create your Pass Type ID (formatted as `pass.com.thewalletcrew.{tenantId}`), generate the signing certificate, configure push notifications, and upload everything to your tenant. This typically completes within 1–3 business days. We’ll confirm by email and share a short summary of what was created.

### Option 2 — configuration on your own

You manage the complete setup within your Apple Developer account and The Wallet Crew admin console. This option requires familiarity with Apple's certificate infrastructure but maintains strict internal access control.

#### Understanding the Components

Before proceeding, it's helpful to understand what you're creating:

Your **Pass Type ID** is the issuer identifier (for example `pass.com.thewalletcrew.{tenantId}`). The **CSR** is a request file generated in The Wallet Crew that Apple uses to create your certificate. The **signing certificate** is what cryptographically signs each pass. The **APNs auth key** is what lets us trigger updates for passes already installed on devices.

Follow these steps to configure your Apple membership program for The Wallet Crew.

{% stepper %}
{% step %}
**Login and open Identifiers**

1. Login to the Apple developer program console:

<p align="center"><a href="https://developer.apple.com/account" class="button secondary" data-icon="chevrons-right">Apple Developer program console</a></p>

2. Go to Certificates, IDs & Profiles > Identifiers
   {% endstep %}

{% step %}
**Create a Pass Type ID**

1. Click the + button and select Pass Type IDs, then click Continue.
2. Fill the form. Set the description to `membership pass`. Set the identifier to the value shown in The Wallet Crew under `pass type identifier`.

   <p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/passTypes/configuration/apple/edit" class="button secondary" data-icon="chevrons-right">The Wallet Crew</a></p>

The value should follow the pattern `pass.com.thewalletcrew.{tenantId}` where `{tenantId}` is your brand identifier.

{% hint style="danger" %}
Treat the Pass Type ID identifier as permanent. Once you’ve issued passes, changing it typically breaks updates and can force a full re-issuance.
{% endhint %}

Copy this exact value and paste it into the Apple Developer Portal identifier field.

<div data-with-frame="true"><figure><img src="/files/74bd6853695801900d221a6c3cf5636279925c29" alt="The Wallet Crew console showing the Pass Type Identifier value to copy into Apple Developer Portal"><figcaption><p>The Wallet Crew console showing the Pass Type Identifier value to copy into Apple Developer Portal</p></figcaption></figure></div>

{% hint style="warning" %}
If you need to modify this identifier for any reason, click the lock icon next to the field in The Wallet Crew console and coordinate the change with your point of contact at The Wallet Crew to ensure proper synchronization. Never do it without the consent of your point of contact at The Wallet Crew.
{% endhint %}

Click **Continue** to review your settings, then click **Register** to create the Pass Type ID.
{% endstep %}

{% step %}
**Navigate to Pass Type ID Details**

After registering your Pass Type ID, you'll be returned to the identifiers list. Locate and click on the Pass Type ID you just created to open its detail page.

<div data-with-frame="true"><figure><img src="/files/b73a553ea9e0ac8d1a976d1f84fae1897df247a3" alt="Apple Developer Portal identifiers list showing the created Pass Type ID"><figcaption><p>Apple Developer Portal identifiers list showing the created Pass Type ID</p></figcaption></figure></div>

In the Pass Type ID details page, click the **Create Certificate** button. This will open Apple's certificate creation workflow

<div align="center" data-with-frame="true"><img src="/files/541b3ddefbc41927611bfb6dd5154e15b094c60a" alt="Apple Developer Portal Pass Type ID details showing the Create Certificate button"></div>

Leave this browser tab open and switch to The Wallet Crew admin console tab. If you don't have it open, navigate to The Wallet Crew Apple Configuration.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/passTypes/configuration/apple/edit" class="button secondary" data-icon="chevrons-right">The Wallet Crew Apple Configuration</a></p>
{% endstep %}

{% step %}
**Generate Certificate Signing Request (CSR)**

In The Wallet Crew console, locate the **Certificate Signing Request (CSR)** section and click **Generate CSR**. The system will create a cryptographic signing request file. Once generation completes, click **Download CSR** to save the file to your computer. The filename will be similar to `pass.cloud.thewalletcrew.{yourbrand}.csr`.

<div><figure><img src="/files/51211bb348c0be83fdc4febd3cef206f196bd55e" alt="The Wallet Crew Apple configuration showing the Generate CSR action"><figcaption><p>The Wallet Crew Apple configuration showing the Generate CSR action</p></figcaption></figure> <figure><img src="/files/7c23971f1d099aa58ef777c9064e1785babf201f" alt="The Wallet Crew Apple configuration showing the Download CSR action"><figcaption><p>The Wallet Crew Apple configuration showing the Download CSR action</p></figcaption></figure></div>
{% endstep %}

{% step %}
**Upload CSR to Apple and download certificate**

Return to the Apple Developer Portal browser tab where the certificate creation form is waiting. Leave the **Certificate name** field empty so Apple auto-generates it, then upload the `.csr` file you downloaded from The Wallet Crew.

Click **Continue** to process the CSR. Apple will generate your signing certificate using the cryptographic information from The Wallet Crew's CSR.

<div><figure><img src="/files/bd007d64d1c0abb475a55a2fcc211c3c9bb52cb6" alt="Apple Developer Portal certificate creation form showing CSR upload"><figcaption><p>Apple Developer Portal certificate creation form showing CSR upload</p></figcaption></figure> <figure><img src="/files/a07d003f6caf273b635ec741972e983fe29ffa9c" alt="Apple Developer Portal certificate download screen for the generated pass certificate"><figcaption><p>Apple Developer Portal certificate download screen for the generated pass certificate</p></figcaption></figure></div>

On the confirmation page, click **Download** to save the certificate file (named `pass.cer`) to your computer. This certificate file is the cryptographic credential that will sign all wallet passes issued by your organization.
{% endstep %}

{% step %}
**Upload certificate to The Wallet Crew**

Navigate back to The Wallet Crew Apple Configuration page. Locate the **Certificate Upload** section.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/passTypes/configuration/apple/edit" class="button secondary" data-icon="chevrons-right">The Wallet Crew Apple Configuration Page</a></p>

Click **Choose File** and select the `pass.cer` certificate file you downloaded from Apple. The Wallet Crew system will validate that the certificate matches your CSR and is properly configured.

Review the certificate information displayed (expiration date, issuer details) and click **Apply Certificate** to complete the upload. The certificate is now active and will be used to sign all wallet passes you create.

<div data-with-frame="true"><figure><img src="/files/6039d8946c9bb92abf38141ddc431ff09ea4d641" alt="The Wallet Crew Apple configuration showing certificate upload and Apply Certificate"><figcaption><p>The Wallet Crew Apple configuration showing certificate upload and Apply Certificate</p></figcaption></figure></div>
{% endstep %}

{% step %}
**Create APNs Auth Key in Apple**

Apple Push Notification service (APNs) enables real-time updates to wallet passes after they've been installed on users' devices. When you update a pass balance, change event details, or modify any pass content, APNs notifies the user's device to download the latest version.

Navigate to the Apple Developer Keys page and click the **+ button** to create a new key.

<p align="center"><a href="https://developer.apple.com/account/resources/authkeys/list" class="button secondary" data-icon="chevrons-right">Apple Developer Keys page</a></p>

Complete the key registration form: Name the key (for example “Wallet Push Notifications”), enable **Apple Push Notifications service (APNs)**, then click **Configure** next to APNs to pick the environment.

In the APNs configuration dialog, select **Production** environment (not Sandbox). Production environment is required for wallet passes to receive updates in real-world usage. Click **Save** to confirm this setting.

<div data-with-frame="true"><figure><img src="/files/230d493e2d9ff95a400389ba2f679d7171802b31" alt="Apple Developer Portal key registration form with APNs enabled"><figcaption><p>Apple Developer Portal key registration form with APNs enabled</p></figcaption></figure></div>

Click **Continue** to review your key configuration, then click **Register** to create the key. Apple will display your Key ID, this is a critical piece of information you'll need in the next step, so copy it to a safe location.

Click **Download** to save your authentication key file (named `AuthKey_XXXXXXXXXX.p8`).

**Important:** Apple only allows you to download this file once. If you lose it, you'll need to revoke this key and create a new one. Store the downloaded `.p8` file securely—treat it like a password.
{% endstep %}

{% step %}
**Upload APNs key to The Wallet Crew**

Navigate to The Wallet Crew APNs Configuration page.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/passTypes/configuration/apple/editApn" class="button secondary" data-icon="chevrons-right">The Wallet Crew APNs Configuration page</a></p>

Complete the APNs configuration form: Paste the **Key ID** you copied from Apple (10 characters) and upload the `AuthKey_XXXXXXXXXX.p8` file you downloaded.

Click **Save** or **Apply** to upload the APNs credentials. The Wallet Crew platform will validate the key and configure push notifications for your tenant.

<div data-with-frame="true"><figure><img src="/files/413914e60d4d2dbb28ab09447e70aa28e5abeeee" alt="The Wallet Crew APNs configuration showing Key ID and .p8 file upload"><figcaption><p>The Wallet Crew APNs configuration showing Key ID and .p8 file upload</p></figcaption></figure></div>

**Configuration complete:** Your Apple Wallet integration is now fully configured. You can create wallet passes, and they will be signed with your certificate and capable of receiving real-time updates via APNs.
{% endstep %}
{% endstepper %}

## Certificate Renewal

Apple Wallet certificates expire annually and must be renewed to continue issuing passes. Apple will send reminder emails before expiration, but you should proactively renew certificates at least two weeks before the expiration date to avoid service interruption.

{% hint style="info" %}
**Timeline:** Certificate renewal takes approximately 15 minutes. Existing passes continue working during renewal, with no downtime.
{% endhint %}

{% hint style="warning" %}

### Renewal does not affect production

Renewing a certificate in staging does not update production. Upload the renewed certificate separately in the production tenant.
{% endhint %}

{% stepper %}
{% step %}
**Initiate Certificate Renewal in Apple**

Navigate to the Apple Developer Account and sign in. Select **Certificates, IDs & Profiles** from the left navigation, then click **Certificates**.

<p align="center"><a href="https://developer.apple.com/account" class="button secondary" data-icon="chevrons-right">Apple Developer Account</a></p>

Click the **+ button** to create a new certificate. Select **Pass Type ID Certificate** from the list of certificate types, then click **Continue**.
{% endstep %}

{% step %}
**Generate CSR in The Wallet Crew**

1. Open The Wallet Crew admin console and click **Generate CSR**. Even if you have a previous CSR file, you must generate a new one for renewal.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/passTypes/configuration/apple/edit" class="button secondary" data-icon="chevrons-right">The Wallet Crew Administration Console - Apple configuration</a></p>

2. Click **Generate CSR** to create a new certificate signing request. Once generation completes, click **Download CSR** to save the file. The filename will be similar to `pass.cloud.thewalletcrew.{yourbrand}.csr`.

<div><figure><img src="/files/51211bb348c0be83fdc4febd3cef206f196bd55e" alt="The Wallet Crew Apple configuration showing Generate CSR for renewal"><figcaption><p>The Wallet Crew Apple configuration showing Generate CSR for renewal</p></figcaption></figure> <figure><img src="/files/7c23971f1d099aa58ef777c9064e1785babf201f" alt="The Wallet Crew Apple configuration showing Download CSR for renewal"><figcaption><p>The Wallet Crew Apple configuration showing Download CSR for renewal</p></figcaption></figure></div>
{% endstep %}

{% step %}
**Upload CSR to Apple and download renewed certificate**

Return to the Apple Developer Portal. In the certificate creation workflow, upload the new CSR file you just downloaded from The Wallet Crew.

Click **Continue** to generate the renewed certificate, then click **Download** to save the new `pass.cer` file.

<div><img src="/files/bd007d64d1c0abb475a55a2fcc211c3c9bb52cb6" alt="Apple Developer Portal certificate creation form showing CSR upload (renewal)"> <img src="/files/737e6991b36a57b2b20e1c35a829a17c1ecf660a" alt="Apple Developer Portal confirmation screen for renewed pass certificate"> <figure><img src="/files/a07d003f6caf273b635ec741972e983fe29ffa9c" alt="Apple Developer Portal download screen for the renewed pass certificate"><figcaption><p>Apple Developer Portal download screen for the renewed pass certificate</p></figcaption></figure></div>
{% endstep %}

{% step %}
**Upload renewed certificate to The Wallet Crew**

Navigate to The Wallet Crew Apple Configuration page. Upload the renewed `pass.cer` certificate file.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/passTypes/configuration/apple/edit" class="button secondary" data-icon="chevrons-right">The Wallet Crew Apple Configuration</a></p>

Review the new expiration date to confirm it's been extended for another year, then click **Apply Certificate**.

**Renewal complete:** Your certificate is renewed for another year. All existing passes continue working seamlessly, and new passes will be signed with the renewed certificate.

<div data-with-frame="true"><figure><img src="/files/6039d8946c9bb92abf38141ddc431ff09ea4d641" alt="The Wallet Crew Apple configuration showing upload of the renewed certificate and Apply Certificate"><figcaption><p>The Wallet Crew Apple configuration showing upload of the renewed certificate and Apply Certificate</p></figcaption></figure></div>
{% endstep %}
{% endstepper %}

## Troubleshoot certificate renewal

### Multiple certificates in Apple Developer

Two certificates for the same Pass Type ID are expected during renewal. The existing certificate remains active while Apple adds the renewed certificate.

The Wallet Crew automatically uses the newest active certificate. The older certificate expires naturally and does not require revocation.

Do not revoke the older certificate while it remains valid. Revocation can briefly interrupt pass issuance before the renewed certificate propagates.

After the older certificate expires, it can be deleted in Apple Developer. Deleting it does not affect The Wallet Crew platform.

### CSR upload shows an older file

During renewal, the CSR upload screen in the admin console may show a dropdown of earlier files. This happens when the browser session caches previously selected files.

Select **Upload new file** or **Browse** beside the dropdown. The link can appear visually de-emphasized but still accepts a new CSR file.

If the link is unavailable, open the page in a private or incognito window. This starts a fresh browser session. If the issue continues, contact The Wallet Crew support with a screenshot. The team can upload the renewed certificate directly to the tenant.

## FAQ

<details>

<summary><strong>What is a Pass Type ID and why do I need one?</strong></summary>

A Pass Type ID is your issuer identifier in Apple’s ecosystem (for example `pass.com.thewalletcrew.{tenantId}`). It tells Apple and iOS devices which organization is allowed to issue and sign passes, which is why it’s required for any Apple Wallet deployment. Most brands use one Pass Type ID across all their pass types.

</details>

<details>

<summary><strong>What's the difference between a CSR, certificate, and APNs key?</strong></summary>

The CSR is a request file generated in The Wallet Crew that you upload to Apple. Apple uses it to generate your signing certificate, which is the credential used to sign every pass. The APNs key is separate. It’s what lets The Wallet Crew authenticate to Apple Push Notification service to trigger updates for passes already installed on devices.

</details>

<details>

<summary><strong>Why do I need a certificate (.cer) and an APNs key (.p8)?</strong></summary>

Apple Wallet splits “trust” into two pieces. The `.cer` certificate signs your passes, so devices can verify the pass is authentic and hasn’t been tampered with. The `.p8` APNs key authenticates the push channel, so Apple accepts update notifications for your passes and devices know they should refresh.

</details>

<details>

<summary><strong>How long does Apple Developer Program enrollment take?</strong></summary>

For organizations, Apple typically approves enrollment in 2–5 business days. Sometimes Apple asks for extra verification around the D‑U‑N‑S number or company identity. The D‑U‑N‑S number is usually sent by email with the subject `Your D-U-N-S Number is enclosed.` from `Apple Developer <developer@email.apple.com>`. Once approved, the wallet certificate setup usually takes around 1–2 hours.

</details>

<details>

<summary><strong>Can I use an individual Apple Developer account instead of organization?</strong></summary>

You technically can, but it’s rarely a good idea. Individual accounts show a personal name on passes and don’t support the same team workflows. Most businesses should enroll as an organization (same $99/year price).

</details>

<details>

<summary><strong>What happens if my certificate expires?</strong></summary>

If the certificate expires, issuing and updating passes can fail. Passes already installed may still display, but they won’t reliably receive updates. Renew at least two weeks before expiration; Apple usually sends reminders about 30 days before.

</details>

<details>

<summary><strong>Do I need to renew the APNs authentication key?</strong></summary>

No. APNs keys do not expire, so you don’t renew them. You normally renew only the Pass Type ID certificate each year. If you revoke the APNs key in Apple’s portal, you must create a new one and upload it to The Wallet Crew.

</details>

<details>

<summary><strong>Can I revoke delegated access after initial setup?</strong></summary>

Yes. Once everything is configured, you can remove the delegated admin user from App Store Connect and the integration will keep working. Delegation is only needed for initial setup, and it’s optional for renewals.

</details>

<details>

<summary><strong>What if I can't find my Pass Type Identifier in The Wallet Crew console?</strong></summary>

You’ll find it on the Apple Configuration page under **Pass Type Identifier**. If it’s empty or errors, contact your point of contact at The Wallet Crew. Your tenant may need a small setup step before Apple configuration is available.

</details>

<details>

<summary><strong>Why must I use "production" APNs environment, not "sandbox"?</strong></summary>

Apple Wallet uses the production APNs environment, even for testing. Sandbox is meant for iOS app development, not passes. If you configure sandbox by mistake, push updates won’t work reliably.

</details>

<details>

<summary><strong>How do I know if my configuration is working correctly?</strong></summary>

Create a test pass in The Wallet Crew and add it to an iPhone. If it installs and shows your organization name, signing works. Then change a simple field (like a balance or text) and confirm the installed pass refreshes within a few seconds.

</details>

<details>

<summary><strong>What should I do with the .p8 APNs key file after uploading?</strong></summary>

Store the `.p8` file like a password, ideally in a password manager or secure document storage. You may need it later for audits, reconfiguration, or if Apple asks you to verify your APNs setup. Don’t commit it to version control and don’t send it over unencrypted email.

</details>

<details>

<summary><strong>Can I use the same Apple Developer account for multiple brands?</strong></summary>

Yes, but each brand should use its own Pass Type ID. One Apple Developer account can host multiple Pass Type IDs, each with its own certificate. In The Wallet Crew, each tenant maps to its own Apple configuration.

</details>

<details>

<summary><strong>We already have existing passes. How do we migrate to The Wallet Crew?</strong></summary>

This is a **migration** of live passes, not a normal “renewal”.

For Apple, the key constraint is issuer identity. In practice, you keep the **same Pass Type ID**, export the existing pass technical data (like serial number + auth token), then repoint updates to The Wallet Crew.

Follow the dedicated guide: [Move passes to The Wallet Crew](/configure/advanced-configuration/wallet/import-and-export/pass-migration/move-passes-to-the-wallet-crew).

If you are leaving The Wallet Crew, use: [Export passes from The Wallet Crew to another provider](/configure/advanced-configuration/wallet/import-and-export/pass-migration/export-passes-from-twc-to-another-provider).

</details>


# Google Wallet Account

Set up Google Pay & Wallet Console access and Google Wallet API credentials so The Wallet Crew can issue passes under your brand.

Configure your Google Wallet integration using either delegated access (recommended for faster setup) or self-managed configuration. This guide covers account creation, API enablement, and credential management for deploying digital wallet passes through The Wallet Crew platform.

## Overview

To distribute digital passes through Google Wallet, your organization must get a Google Pay & Wallet Console issuer account approved and configure a Google Cloud project for API access. Google approves issuers manually, so plan **3–5 business days** for approval, plus **15–60 minutes** for the technical setup.

**Main things to configure**

* A Google Pay & Wallet Console issuer account (approval required)
* A Google Cloud project with Google Wallet API access

You’ll create the core Google services under your brand (Google Cloud project + Google Pay & Wallet Console approval). Then you’ll either delegate the remaining configuration to The Wallet Crew, or complete it yourself and paste the required values into The Wallet Crew.

Want the “why” before the “how”? Start with [Apple & Google wallet](/configure/advanced-configuration/wallet/apple-and-google-wallet).

#### Prerequisites

* Google Workspace or Gmail account with admin privileges
* Company information for Google Pay merchant verification
* Authority to create service accounts in Google Cloud

## Google Cloud project configuration

Navigate to the Google Cloud Console and sign in with your company Google account.

<p align="center"><a href="https://console.cloud.google.com/iam-admin/" class="button secondary" data-icon="chevrons-right">Google Cloud Console</a></p>

Create a new project using the naming convention `thewalletcrew-<brandName>` where `<brandName>` matches your organization or brand identifier. For example: `thewalletcrew-acmecorp` or `thewalletcrew-retailstore`. This naming helps identify the project's purpose at a glance.

### Account delegation

This approach allows The Wallet Crew team to handle the technical configuration while you retain ownership of all accounts and credentials. You'll grant temporary access, and we'll configure everything according to best practices.

In the IAM & Admin section, select **IAM** from the left navigation menu. Click the **Grant Access** button and add `contact@neostore.cloud` as a project owner. This permission level allows The Wallet Crew team to create service accounts, enable APIs, and configure all necessary resources. You can revoke this access after initial setup is complete.

<div data-with-frame="true"><figure><img src="/files/743125a55c555a373c65e1bcb379f1dbde9abe0a" alt="Google Cloud IAM page showing the Grant access action" width="375"><figcaption><p>Google Cloud IAM: grant project access</p></figcaption></figure></div>

This way, the Google Wallet passes are issued under your organization's identity, not The Wallet Crew's. The project you create here establishes that organizational identity in Google's systems.

### Configuration on your own

You manage the full setup within your own Google Cloud and Google Pay accounts.

To access the Google Pay & Wallet Console, you need to [sign up](https://support.google.com/pay/merchants/contact/instore_merchants). After you submit the form, the support team will contact you to validate your use case and enable your issuer account.

{% stepper %}
{% step %}
**Create a service account**

1. Go to the Credentials page.

<p align="center"><a href="https://console.developers.google.com/apis/credentials" class="button secondary" data-icon="chevrons-right">Google Cloud - Credential Page</a></p>

2. Ensure the current project is `thewalletcrew-<brandName>`
3. Click **Create credentials → Service account**.

<div data-with-frame="true"><figure><img src="/files/eONdeRsugzBli2GuUMeu" alt="Google Cloud: Create credentials → Service account" width="375"><figcaption><p>Create a new service account</p></figcaption></figure></div>

4. Fill the form:

* Service account name: `TheWalletCrew`
* Service account id: keep the autogenerated value

<figure><img src="/files/yAAbWfhc5fUyYBw6javO" alt="Google Cloud service account details form (name and ID)" width="375"><figcaption><p>Service account name and ID</p></figcaption></figure>

5. Click **Done** to complete the service account creation.

Note the email address generated for the service account. Example: `thewalletcrew@thewalletcrew-123456.iam.gserviceaccount.com`. You’ll need it later in the Google Pay & Wallet Console.
{% endstep %}

{% step %}
**Create and download a JSON key**

1. Open the service account you just created. Then go to the **Keys** tab.

<div><figure><img src="/files/OC0MDI7eJCE3E7aWriV8" alt="Google Cloud service account: Keys tab"><figcaption><p>Open the Keys tab</p></figcaption></figure> <figure><img src="/files/DaljC6xPOd1bxwVgO96Y" alt="Google Cloud service account keys page showing the Add key action"><figcaption><p>Create a new key</p></figcaption></figure></div>

2. Click **Add key → Create new key**.

<div data-with-frame="true"><figure><img src="/files/OU91pWlhxoDlj3pjmR13" alt="Google Cloud: Add key → Create new key" width="375"><figcaption><p>Start creating a JSON key</p></figcaption></figure></div>

3. Choose **JSON** and click **Create**.

<figure><img src="/files/3EIqAXRmYKz30fmw2IJf" alt="Google Cloud: select JSON as the key type" width="375"><figcaption><p>Select JSON key type</p></figcaption></figure>

4. Save the generated file to a secure location. You’ll upload it later in The Wallet Crew admin console.

{% hint style="warning" %}
Treat this JSON file like a password.
{% endhint %}
{% endstep %}

{% step %}
**Enable the Google Wallet API**

Go to the Google Wallet API page and enable API access.

<p align="center"><a href="https://console.cloud.google.com/apis/library/walletobjects.googleapis.com" class="button secondary" data-icon="chevrons-right">Google Wallet API</a></p>

<div data-with-frame="true"><figure><img src="/files/U0ymOiSmRKoDEpzfcyDu" alt="Google Cloud API Library: enable Google Wallet API (walletobjects.googleapis.com)" width="375"><figcaption><p>Enable <code>walletobjects.googleapis.com</code></p></figcaption></figure></div>
{% endstep %}
{% endstepper %}

## Google Pay & Wallet Console configuration

Navigate to the Google Pay & Wallet Console and sign in with your company Google account.

<p align="center"><a href="https://pay.google.com/gp/m/issuer/list" class="button secondary" data-icon="chevrons-right">Google Pay &#x26; Wallet Console</a></p>

### Account delegation

Navigate to the Users section. Add `contact@neostore.cloud` with **Administrator** permission. This allows The Wallet Crew team to configure your issuer settings and complete the integration.

<div data-with-frame="true"><figure><img src="/files/c095b3257b083c5ef092780d822e4603c2d39225" alt="Google Pay &#x26; Wallet Console Users page showing user access management" width="375"><figcaption><p>Add a user with <strong>Adminstrator</strong> access</p></figcaption></figure></div>

The Wallet Crew team will receive a notification of your access grant and will proceed with service account creation, API enablement, and credential configuration. We'll notify you when the setup is complete and provide you with your credentials for safekeeping.

### Configuration on your own

{% stepper %}
{% step %}
**Invite the service account**

1. Navigate to the Users section.

<div data-with-frame="true"><figure><img src="/files/LyhLOQ8McyQXEbLP44WI" alt="Google Pay &#x26; Wallet Console navigation highlighting Users" width="375"><figcaption><p>Open the Users section</p></figcaption></figure></div>

2. Click **Invite a user**.

Fill the form with the following information:

* Email address: the one noted at step 1.4
* Access level: **Developer**

<div><figure><img src="/files/iREvmk3QTE7so7zz711c" alt="Google Pay &#x26; Wallet Console: Invite a user dialog"><figcaption><p>Invite the service account email</p></figcaption></figure> <figure><img src="/files/lYe1IWhjKYmbNS9cHSkd" alt="Google Pay &#x26; Wallet Console: select Developer access level"><figcaption><p>Choose the <strong>Developer</strong> role</p></figcaption></figure></div>

Then click **Invite**.

<div data-with-frame="true"><figure><img src="/files/7iTBtFC6Lj2pbr6j1U4g" alt="Google Pay &#x26; Wallet Console: Invite button to send the user invitation" width="375"><figcaption><p>Send the invitation</p></figcaption></figure></div>
{% endstep %}

{% step %}
**Complete establishment information**

1. Click **Establishment details** and verify that all the information is filled and approved.

<div data-with-frame="true"><figure><img src="/files/0VwswtA0TqExd7k0mgRn" alt="Google Pay &#x26; Wallet Console: establishment details page" width="375"><figcaption><p>Confirm establishment details are approved</p></figcaption></figure></div>

2. Click **Google Wallet API**.

<figure><img src="/files/3bfDyqNCQ7UgZ0iffUnv" alt="Google Pay &#x26; Wallet Console: Google Wallet API page showing the issuerId value" width="375"><figcaption><p>Copy the <code>issuerId</code></p></figcaption></figure>

Note the `issuerId`. You’ll need it in The Wallet Crew admin console.
{% endstep %}
{% endstepper %}

## Configure The Wallet Crew

If you configure on your own, go back to The Wallet Crew admin console and open Wallet > Configuration > Google.

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/passTypes/configuration/google" class="button secondary" data-icon="wallet">Wallet > Configuration > Google</a></p>

Fill the form with:

* the service account JSON key you downloaded earlier
* the `issuerId` from the Google Pay & Wallet Console

<figure><img src="/files/CDQiRFpaMdlH4w4R64pz" alt="The Wallet Crew admin console: Google Wallet configuration form for issuerId and service account JSON key"><figcaption><p>Paste <code>issuerId</code> and upload the JSON key</p></figcaption></figure>

#### Request public access (only if needed)

If after testing with a Google pass you get the following error:

<div data-with-frame="true"><figure><img src="/files/3n5QmmvO99wI2vo4hWek" alt="Google Wallet error message asking to request public access" width="297"><figcaption><p>Error when public access is required</p></figcaption></figure></div>

Go back to Google Wallet API:

<div data-with-frame="true"><figure><img src="/files/bETJzX52hricLqJgB5WH" alt="Google Cloud: Google Wallet API console for requesting public access" width="375"><figcaption><p>Request public access from Google</p></figcaption></figure></div>

Then ask for public access. You can use one of these templates.

<details>

<summary><strong>Email template — loyalty card usage</strong></summary>

> Hello,
>
> We'd like to use the Google Wallet API to generate loyalty cards in-store. The customer can scan a QR code (example: xxxx), then create or retrieve their account and add a loyalty card to their wallet.
>
> We work with The Wallet Crew for this.
>
> Regards,

</details>

<details>

<summary><strong>Email template — event usage</strong></summary>

> Hello,
>
> We'd like to use the Google Wallet API to generate event tickets. The customer will receive an email with a download link and add their tickets to their wallet. We will also display an “Add to Wallet” button on our website after purchasing tickets.
>
> We work with The Wallet Crew for this.
>
> Regards,

</details>

## FAQ

<details>

<summary><strong>How long does Google approval take?</strong></summary>

Google approves issuer access manually. Plan **3–5 business days** for approval. Then plan **15–60 minutes** for the technical setup (service account, API enablement, and issuer configuration).

</details>

<details>

<summary><strong>What do we need to configure in The Wallet Crew administration console?</strong></summary>

You need two things: a **service account JSON key** from Google Cloud (service account → **Keys**) and your **`issuerId`** from the **Google Pay & Wallet Console** (Google Wallet API section). Once you paste/upload these in Wallet > Configuration > Google, The Wallet Crew can authenticate and issue passes under your issuer.

</details>

<details>

<summary><strong>Do we need a dedicated Google Cloud project?</strong></summary>

Yes. A dedicated project keeps wallet configuration isolated from other cloud workloads. It also makes access review, billing, and auditing much easier.

</details>

<details>

<summary><strong>What is the “service account” used for?</strong></summary>

The service account is the machine identity used to call Google Wallet APIs server-to-server. It is not a human user. The Wallet Crew uses the service account JSON key to authenticate those API calls.

</details>

<details>

<summary><strong>How should we store the service account JSON key?</strong></summary>

Treat the JSON key like a password. Upload it to The Wallet Crew over the admin console, then store it only in your secret manager (or delete it if you don’t need to keep a copy). Avoid sharing it over chat or email, and rotate it immediately if exposed.

</details>

<details>

<summary><strong>Why do we need to invite a user/service account in Google Pay &#x26; Wallet Console ?</strong></summary>

Google Pay & Wallet Console controls who can manage your issuer. If the service account is not invited, Google Wallet API calls will fail even if the Cloud project is correctly configured. In self-managed setup, invite the **service account** as a user with the **Developer** role.

</details>

<details>

<summary><strong>What does “Enable the Google Wallet API” actually do?</strong></summary>

It enables the Google Wallet API endpoint (`walletobjects.googleapis.com`) in your Cloud project. Without this, requests will fail with authorization errors such as “API not enabled”.

</details>

<details>

<summary><strong>We get an error asking for “public access”. What does it mean?</strong></summary>

Some issuers need an extra approval step from Google before they can distribute passes broadly. This often shows up when you move from testing to real-world distribution. Use the email templates in this guide to request public access from Google.

</details>

<details>

<summary><strong>Can we revoke delegated access after go-live?</strong></summary>

**Yes**. Once you’ve validated that issuance and pass updates work end-to-end, revoke delegated access in both places: remove The Wallet Crew from your **Google Cloud** project IAM, and remove the user from the **Google Pay & Wallet Console** Users list. Do this only after you’ve run real saves and at least one successful update, so you don’t accidentally break production.

</details>

<details>

<summary><strong>Should we renew the configuration yearly?</strong></summary>

Usually **no**. This setup is not something you “renew” on a schedule.

Only redo the configuration in The Wallet Crew if something changed on the Google side, for example:

* You **rotated or replaced** the service account JSON key.
* The key was **revoked/disabled**, or you suspect it was exposed.
* You switched to a **different Cloud project** or **issuerId**.
* IAM / Console permissions were changed and issuance stopped working.

If nothing changed and passes still issue/update correctly, leave it as-is.

</details>

<details>

<summary><strong>We already have existing passes. How do we migrate to The Wallet Crew?</strong></summary>

This is a **migration** of live passes, not a normal “reconfigure”.

On Google, your passes are tied to a **Google Pay & Wallet Console issuer account**. You can’t transfer live passes to a different issuer. Plan to keep the same issuer and move the operational setup (credentials + pass data) to The Wallet Crew.

Follow the dedicated guide: [Move passes to The Wallet Crew](broken://pages/V551Qd8QNz2KEKmMjupc).

</details>


# Template configuration


# How to Create a Template

Customize your wallet pass look and layout: colors, logos/images, field layout, additional info, and links for Apple Wallet and Google Wallet.

## Overview

Creating a pass template is simple and quick. To do this, go to the Template section under the Wallet tab and click on "Create a new template"

<figure><img src="/files/TKsOkqzCaDvabfrJi4uF" alt="How to create a template"><figcaption></figcaption></figure>

You will have several possibilities to create your template.

<figure><img src="/files/1N8x4bNDui6TY4J0mwsJ" alt="How to create a template (2)"><figcaption></figcaption></figure>

### Duplicate a template

If you click on "duplicate" you will be able to create a new template based on an existing one. It will retrieve its configuration, only the name will be different. You will then be able to modify your new template.

First of all, choose in the list the existing template you would like to duplicate and once done click on "ok".

<figure><img src="/files/2ECRMELleXRCrgLnGmDR" alt="Duplicate a template"><figcaption></figcaption></figure>

Choose a new name to create a new template based on the one you selected in the list and click on "confirm template".

<figure><img src="/files/CeoZyP4zuEcFgQHalF9j" alt="Duplicate a template (2)"><figcaption></figcaption></figure>

{% hint style="warning" %}
**If you decide to keep the same name you will overwrite the existing template you selected and linked passes will update on their next update. If this is what you want to do, click on "I confirm overwrite".**
{% endhint %}

<figure><img src="/files/I34BGDnqPJFGu50ubUVk" alt="If you decide to keep the same name you will overwrite the existing template you selected and linked passes will update on their next update. If this is what you want to do, click on I confirm overwrite."><figcaption></figcaption></figure>

### Import a template file

You can also create a new template by importing the configuration of an existing template. For example, if you worked on a template on your staging environment and need to put it in your production environment, you can export your template configuration in staging to import it in production. **⚠️ This only works with a template file from The Wallet Crew.**

You first need to select the template you would like to export, click on the three dots on the right of the template and export configuration. You will see that a pttwc file has been downloaded.

<figure><img src="/files/AWtbH3CYPZ1MakubOxqD" alt="Import a template file"><figcaption></figcaption></figure>

Go back to the creation of a template by clicking on "Create a new template" and choose "Import".

<figure><img src="/files/x3YEVlpv14XTdHm5CIZs" alt="Import a template file (2)"><figcaption></figcaption></figure>

Click on "Upload (template.pttwc)" and select the pttwc file you just downloaded.

<figure><img src="/files/y5JEIAjgUznzNG0SUYxW" alt="Import a template file (3)"><figcaption></figcaption></figure>

Choose a new name to create a new template based on the file your imported and click on "confirm template".

<figure><img src="/files/KJuPrutWXw4dXzYahVW8" alt="Import a template file (4)"><figcaption></figcaption></figure>

**⚠️ If you decide to choose a template name already existing on your template list, you will overwrite the template already existing and linked passes will update on their next update. If this is what you want to do, click on "I confirm overwrite".**

<figure><img src="/files/Jqz5sKjPaoNV6Ccsnsga" alt="⚠️ If you decide to choose a template name already existing on your template list, you will overwrite the template already existing and linked passes will update on their next update. If this is what you want to do, click on I confirm overwrite."><figcaption></figcaption></figure>

### Use a pre-built template

The Wallet Crew has created and centralized a template library that you can use to create your new templates based on your use case. If you use one of the pre-built template, your new template will have the same configuration as the pre-built one (colors, images, fields), and you will be able to keep the configuration or modify some elements. To access this library, after clicking on "Create a new template", select "Use a pre-built".

<figure><img src="/files/i578cB7sck2CrodxUTsY" alt="Use a pre-built template"><figcaption></figcaption></figure>

You have the choice between customer card, event ticket, generic, gift cards, and offer templates. Use [Type of pass](https://docs.thewalletcrew.io/guides-design/) to pick the right starting point for your use case.

Before selecting the pre-built template you would like to use, you can see what the Apple and the Google version look like.

<figure><img src="/files/FQMgI4Ps2KJFgenQRUv9" alt="Use a pre-built template (2)"><figcaption></figcaption></figure>

Once you have made your choice, select your pre-built template by clicking on "Use this template".

<figure><img src="/files/RxXBguMac4lhdEoFhbr4" alt="Use a pre-built template (3)"><figcaption></figcaption></figure>

Choose a new name to create a new template based on the pre-built one and click on "confirm template".

<figure><img src="/files/YO1V5oZiuyfVLjoduhRE" alt="Use a pre-built template (4)"><figcaption></figcaption></figure>

**⚠️ If you decide to choose a template name already existing on your template list, you will overwrite the template already existing and linked passes will update on their next update. If this is what you want to do, click on "I confirm overwrite".**

<figure><img src="/files/Jqz5sKjPaoNV6Ccsnsga" alt="⚠️ If you decide to choose a template name already existing on your template list, you will overwrite the template already existing and linked passes will update on their next update. If this is what you want to do, click on I confirm overwrite. (2)"><figcaption></figcaption></figure>

### Start with AI

The Wallet Crew offers you the possibility of playing with an AI template designer to find inspiration and ideas before creating your new template. Here are a few things to know before using this tool :

* This tool is in beta mode, which means that it's brand new and may contain errors
* You need a Google account to access this feature
* The template you create in the template designer can not be exported and imported on The Wallet Crew
* The template designer is for now only in French

If you wish to use it, once you have clicked on "Create a new template", select "Start with AI".

<figure><img src="/files/zrhT1URRTaT4OPy6d9se" alt="Start with AI"><figcaption></figcaption></figure>

### What's next?

You new template is now created! To modify it, find your recently created template in the list of templates. To access the Apple version, click on the corresponding logo.

From this interface, you will have the ability to customize the loyalty card according to your needs:

* Logo and colors of your company
* Customer’s name
* Primary, secondary fields
* Backfields informations
* Barcode for identification at the checkout
* Strip

**And much more.**

<figure><img src="/files/R2ZSw2I1iQiqCj7nsrIV" alt="And much more."><figcaption></figcaption></figure>

To customize the Android version, Simply switch by clicking on "Google". You will have the ability, just like with the Apple version, to customize the fields and design of your pass template to your liking.

<figure><img src="/files/Yg1GB0oWEEH6thIVqO77" alt="What&#x27;s next"><figcaption></figcaption></figure>

To learn more about how to configure a template, start with [Type of pass](https://docs.thewalletcrew.io/guides-design/).


# Cards design (colors, images, and fields)

Customize your wallet pass look and layout: colors, logos/images, field layout, additional info, and links for Apple Wallet and Google Wallet.

## Card design

Design a card for your customers to simplify their in-store experience and match with your brand identity.

### **Graphic design**

In the "Graphic design" section, you can customize the pictures on the card and its color, which allows the card to be as close as possible to the company's corporate style.

#### **Card color**

To adjust the card color:

1. Press the colored code box and select the desired color for card background;

![Card color](/files/pGGU8qmCQdRAJNJYOqak)

2. If necessary, change the header and text colors on the card by moving the sliders to the right and following the same steps with color selection (only for cards in Apple Wallet);

![Card color (2)](/files/O2lZp6j5s9ptDnkDeIu9)

3. Check the color on the cards on the right side of the interface.

![Card color (3)](/files/9ywS6ytbzLaLGwuR7cKD)

❗ Please, note: If you have a branded company color, enter its code in the area next to the colored box. This will help you to get the exact color. Please note that the color of the card can be a solid color only.

![Card color (4)](/files/S26mqnzz8AJFOELS0P1q)

#### **Images on the card**

Two images can be placed on the card at the same time: the company logo and the central image.

![Images on the card](/files/zqvctT2YeHFM5WhC5Bac)

**Apple Wallet card**

1. Upload your logo in the appropriate section. The preferred file type is PNG (with transparent background), 480 x 150px;2.

Upload your center image in the appropriate section. Preferred PNG file type, 1125 x 432px.

**Google Wallet card**

1. Upload your logo in the appropriate section. Preferably PNG file type (with the same background color as the card color), minimum size 820 x 820px;2. Upload the center image in the appropriate section. Preferred PNG file type, 1032 x 336px.

❗ Please, note: You can enhance and move the image areas with the mouse to select them more accurately.

#### **Fields layout**

In the "Fields layout" section, you can select the information that will be displayed on your customers' card.To add fields to the card:1. Select fields from the drop-down list;2. Check the layout of the fields on the cards on the right side of the interface;3. Click Save.

The fields on the card will show you the information from the variables you've created and display the information that is relevant to the client. The information inside the fields is updated automatically.

#### **Additional information**

In the "Additional information" section you can add all the necessary information for the customer, such as:

* Promotions and news from the company;
* Terms and conditions of the loyalty program;
* Company's contacts;
* Purchase history;
* Other information that is important for you to display.

![Additional information](/files/WTkQ3BT1NfuilMRpvLuF)

To add a new field with information, click the "+ Add field" button and enter its name and description in the fields that appear. To have the field display updated information, add a variable.You can edit the fields and change their places, and delete them by clicking on the "Hide" button.

#### **Links**

In the “Links” section, you can leave links that will allow your customers to communicate with you and get to the websites in one click.

For example:

* Company website;
* Order tracking;
* Online appointment;
* Stores infos
* Other links that are important for you to share.

![Links](/files/4A9bbkW5zWsYdJINC0fO)


# How to Translate a template

## **Importance of multilingual cards**

In the retail or the event worlds, it is crucial to offer cards in different languages to cater to an increasingly international clientele. Providing a multilingual pass also helps avoid any misinterpretation, which is particularly essential during events.

### **Steps to manage translations of a pass template**

Go to "Settings" then to "General".

![Steps to manage translations of a pass template](/files/MvsBaogYBNs91tWEDgVj)

In the internationalization section, you have the option to add the languages you want. For example, to add the Spanish language, simply enter the ISO code for the language, which is "es". Then, click on the small cross to confirm before saving.

**You can find the ISO code of a language** [**right here**](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes)**{target="\_blank"}.**

![You can find the ISO code of a language](/files/iZz1avJLhBuHmGrsusXK)

You can add as many languages as you want.

![Steps to manage translations of a pass template (2)](/files/t24DQh5cSBKePfpLETqH)

To set a default language, just click on the chosen language. Don't forget to click on "save" on the top of the screen.

![Steps to manage translations of a pass template (3)](/files/Y5L1bm3oSzQvJI1eVmON)

Now, in the template menu, select your template. You will find the newly added languages. Click on one of them to preview the card.

![Now, in the template menu, select your template. You will find the newly added languages. Click on o](/files/4Pmzf1mrFkk4ReOMj21A)

To translate a field, click on this small icon:

![To translate a field, click on this small icon](/files/eH4eM2ll9baRg5eblVq0)

You will have the option to translate according to the languages.

![You will have the option to translate according to the languages](/files/6NpSHMDd2cKfL3UfgL68)

⚠️ **You can only translate a field that has the translation icon.**

### **Steps for bulk translation**

If you have many languages and don't want to lose time translating the fields one by one on the template editor, you can bulk edit them! To do so, you have to go on the "Locales" section, in the "Tools" menu.

![Steps for bulk translation](/files/JhF33wPiARMhebKLlh1X)

Choose the pass template you want to translate, click on the three dots on the right and click on "bulk edit".

![Steps for bulk translation (2)](/files/Gghfk3r2Scr6jn4MLuzC)

From this interface, you can translate all the fields.

![Steps for bulk translation (3)](/files/E2gWmb35sPnIirrgXfQt)

Fields highlighted in orange indicate that they have not yet been translated. Simply translate the fields to the corresponding language before saving.

![Steps for bulk translation (4)](/files/XiyH4LSt1Nu5vZLbVOJh)

You can export the file in Excel format for easier handling.

![Steps for bulk translation (5)](/files/frKJBsnDLDAQMaIo7pev)

Once you've done modifying your Excel file, you can import it on The Wallet Crew.

![Once you've done modifying your Excel file, you can import it on The Wallet Crew](/files/PqJuf4ITIcESrB3G9GbJ)


# Wallet Card Security

Apple Wallet and Google Wallet pass security at The Wallet Crew (WaaS): GDPR/CCPA, EU data residency, encryption, tenant isolation, and signed “Add to Wallet” links.

## Apple Wallet and Google Wallet pass security

The Wallet Crew is a white-label Wallet as a Service (WaaS) platform. We help brands issue secure **mobile wallet cards** and **wallet passes**. These passes work in **Apple Wallet** and **Google Wallet**.

Common use cases include loyalty cards, gift cards, coupons, and tickets.

This page covers end-to-end wallet pass security:

* privacy and compliance (GDPR, CCPA)
* EU hosting and data residency
* encryption in transit and at rest
* API authentication, throttling, and abuse protection
* secure pass distribution (email, web, QR, NFC)
* Apple Wallet vs Google Wallet update flows

## Compliance and data protection (GDPR, CCPA)

Security and privacy are built into the platform. The Wallet Crew aligns with GDPR and CCPA requirements.

PII is not stored by default. When PII processing is needed, it is driven by your configuration and use case.

Our infrastructure runs on Microsoft Azure in Europe. This supports EU data residency requirements for many organizations.

#### References

* We maintain a documented Security Insurance Plan (SIP). It covers security controls and risk management. Read it here: [Security Insurance Plan (SIP)](/policies/privacy-and-security/security-insurance-plan).
* We also provide a Data Processing Agreement (DPA) model. It defines compliance responsibilities. Read it here: [Data Processing Agreement model](/policies/privacy-and-security/data-processing-agreement-model).
* For practical privacy details, see: [Data Protection FAQ](/policies/privacy-and-security/data-protection-faq).
* For consent capture and evidence, see: [Consents & GDPR compliance](/guides-animation/engage-and-animate/automatisation/push-notifications/consents-and-gdpr-compliance).

## Security Architecture

The Wallet Crew is a multi-tenant platform with strict tenant isolation. Data and operations are segregated between brands. Per-tenant throttling reduces abuse and noisy-neighbor risk.

API authentication supports **OAuth 2.0** and **API keys**. Back-office access uses **Auth0** for identity and access management.

Internal services run inside a dedicated **Azure Virtual Network**. This network is not publicly accessible. Public traffic is routed through **Cloudflare**. Cloudflare provides CDN, **WAF**, DDoS protection, and rate limiting.

We support **custom domains** for pass distribution. Brands can use a subdomain on their own domain. TLS certificates are managed via Cloudflare by default. Brands can also bring their own certificate and DNS configuration.

All communications use TLS 1.2 or TLS 1.3. Data at rest is stored in Azure Cosmos DB and encrypted by Azure. Analytics data is stored in Azure Data Explorer and encrypted by Azure. See [Insights API](https://docs.thewalletcrew.io/api-reference/) for usage and analytics access patterns.

Service-to-service traffic inside the virtual network is also encrypted with TLS.

For hosting details, see [Infrastructure](/developers-guides/pass-architecture/infrastructure).

## Wallet pass distribution security (links, email, QR, NFC)

The Wallet Crew supports secure pass distribution to end users. All channels enforce HTTPS and use signed parameters. This prevents tampering, replay, and unauthorized access.

Each pass in our system is associated with two types of identifiers:

* **Internal identifier**: An opaque, non-sequential UUID generated by The Wallet Crew. It is unique and not guessable. It is safe for direct retrieval.
* **External identifier**: Provided by your systems. Examples include loyalty numbers, ticket numbers, and gift card IDs. These values are often sequential or predictable. Predictable IDs must be protected to prevent enumeration (IDOR) attacks.

To secure retrieval based on external identifiers, we support several mechanisms. They are designed to prevent enumeration and replay attacks.

* HMAC-SHA256 Signature\
  Compute an HMAC with SHA-256 and a tenant-specific shared secret. Your system signs the external identifier. The Wallet Crew verifies the signature before granting access.
* Shared Secret Token\
  Generate a token using a secret shared with The Wallet Crew. Send the token with the identifier. Our API validates it before returning any pass data.
* JWT (JSON Web Token)\
  Use a signed JWT that includes the external identifier as a claim. Sign with HMAC or an asymmetric key pair (RSA/ECDSA). The Wallet Crew validates signature, expiry, and claims.

These controls apply to API retrieval and to distribution links. That includes email, QR codes, and NFC tags. Identifiers in URLs are useless without a valid token.

Passes can be distributed via email using secure “Add to Wallet” links. Email flows integrate with major marketing automation tools. See [Via Email](/guides-enrolment/enrolment/via-email) and [Integrations](https://www.thewalletcrew.com/en/integrations).

For web distribution, we provide an SDK for an “Add to Wallet” button. The SDK keeps the browser-to-platform flow secure. See [On your website](/guides-enrolment/enrolment/on-your-website).

We also provide secure enrolment forms. They can add verification steps before pass access. See [Enrolment form design](/guides-enrolment/enrolment/enrolment-form).

You can also embed secure links into physical touchpoints. Use QR codes on flyers or NFC tags on plastic cards. These links are signed and can be one-time or time-limited. We also offer a web app that displays temporary QR codes. Contact support to pick the right setup for your use case.

## Mobile wallet data flow and privacy

The Wallet Crew is designed to minimize PII storage. PII is not persisted by default.

For performance, some connectors can use an optional temporary cache. Typical cache duration is under 15 minutes. Cache data can be deleted via The Wallet Crew API. Data deletion requests can also be handled through our support team.

Our architecture ensures that sensitive operations occur within secure boundaries.

![Data flow diagram](/files/c94abb9f99618c35fe3ede42b17f675d0702e65c)

## Apple Wallet and Google Wallet communication flows

Communication with wallet providers differs between Apple and Google.

* Apple Wallet\
  Passes are installed on the user’s device. They are not stored on Apple servers by default. Updates are triggered via Apple Push Notification service (APNs). APNs tells the device to fetch the updated pass asynchronously. Passes may sync via iCloud, but we cannot access iCloud content.

  ![Apple Wallet flow](/files/6e6b952f507b58250d5a1a5589880a2e59caf7a8)
* Google Wallet\
  Passes are stored in the user’s Google account. Updates are managed through the Google Wallet API using OAuth credentials. Device delivery and refresh are handled by Google.

  ![Google Wallet flow](/files/263ad45b4beab1de7c1d1bcf9b69b09bc9a78aba)

## API security (authentication, rate limiting, audit logs)

Our APIs are protected with per-tenant rate limiting. Additional controls mitigate brute-force and token abuse.

Audit logs are available on request for compliance and forensic analysis. Platform usage signals are available via the[ Insights API](/developers-guides/integration-guides/insights-api).

## Monitoring and Incident Response

We use Azure Application Insights for monitoring and anomaly detection. Alerts are automated and tuned for suspicious patterns.

We maintain an incident response process and a business recovery plan.

## Risk Mitigation

We enforce HTTPS and signed URLs across all distribution channels. QR codes and NFC tags can be configured as temporary or one-time use. Tenant isolation and throttling further reduce abuse and unauthorized access.

## Quick security FAQ

<details>

<summary>Does The Wallet Crew store personal data (PII)?</summary>

By default, no. The Wallet Crew is designed so PII is not persisted. Some connectors may use an optional short-lived cache.

</details>

<details>

<summary>Are Apple Wallet passes stored on Apple servers?</summary>

Apple Wallet passes are installed on the user’s device. Updates are triggered through APNs. The Wallet Crew cannot access iCloud-stored pass content.

</details>

<details>

<summary>How are “Add to Wallet” links secured?</summary>

All distribution links use HTTPS. Links are signed and validated server-side. We support HMAC-SHA256, shared secret tokens, and JWT. This prevents tampering and pass enumeration.

</details>

<details>

<summary>How does The Wallet Crew prevent abuse of your APIs?</summary>

We use per-tenant rate limiting and additional abuse protections. We monitor anomalies and maintain an incident response process. Audit logs can be provided on request.

</details>


# Import & Export

## Import your passes to The Wallet Crew

The Wallet Crew provides a powerful import tool that allows you to bulk import or update passes using XLSX files. This guide will walk you through the process and explain important considerations.

### Overview

The import tool supports:

* Bulk creation of new passes
* Updating existing passes
* Handling different pass types
* Managing pass identifiers and additional data
* Progress tracking and error reporting

### Before You Begin

1. **File Format**: Prepare your XLSX file with the following considerations:
   * Column names should be clean and avoid special characters
   * Data should be properly formatted according to the expected types
   * The file should contain all necessary pass information
2. **Required Columns**:
   * `id` (optional): If present, used to identify existing passes
   * `passType` (optional): The type of pass. If not specified, you'll need to select a default type
   * Other columns will be treated as additional data
3. **Data Validation**:
   * Email addresses should be properly formatted
   * Phone numbers should follow standard formats
   * Dates should be in a consistent format

### Import Process

#### Step 1: Access the Import Tool

1. Navigate to the **Passes** section in your Wallet Crew account
2. Click the **Import Passes** button
3. Select your XLSX file\
   ![Passes List](/files/LhyafaiUCqZLkcaAQkIU)

#### Step 2: Configure Import Settings

The import modal will show you two important settings:

1. **Discriminator Column**:
   * If your file has an `id` column, it will be automatically selected
   * Otherwise, choose a column that uniquely identifies each pass
   * This column will be used to determine if a pass should be created or updated
2. **Default Pass Type**:
   * Select the default pass type for passes that don't specify one
   * This is required if your file doesn't include a `passType` column

#### Step 3: Review and Import

1. Review the total number of passes to be imported
2. Check that the discriminator and pass type settings are correct
3. Click **Import** to begin the process\
   ![Import Modal](/files/Ly4HxKQbtQWdyePsrD7N)

#### Step 4: Monitor Progress

During the import:

* A progress bar shows the current status
* You can see the number of passes created and updated
* Any errors are displayed in real-time
* You can cancel the import at any time\
  ![Import Progress](/files/aMftxDMNhch9517Bgofb)

### Important Notes

1. **Batch Processing**:
   * Passes are imported in batches of 16 for optimal performance
   * The process continues even if some passes fail to import
2. **Error Handling**:
   * Invalid data formats are reported
   * Missing required fields are highlighted
   * You can review errors and make corrections
3. **Cancellation**:
   * You can cancel the import at any time
   * The browser window should remain open during the process
4. **Data Processing**:
   * Empty values are converted to `null`
   * Special columns (id, secret, creationDate, etc.) are excluded from additional data
   * Metadata fields are handled separately

### After Import

1. The page will automatically refresh to show the updated passes once you close the modal
2. You can review the import report showing:
   * Number of passes created
   * Number of passes updated
   * Any errors that occurred

### Best Practices

1. **Data Preparation**:
   * Clean your data before import
   * Use consistent formatting
   * Validate email addresses and phone numbers
2. **File Structure**:
   * Keep column names simple and clear
   * Use standard date formats
   * Include all required fields
3. **Large Imports**:
   * For large files, consider splitting them into smaller batches
   * Monitor the progress and check for errors
   * Keep the browser window open during import

### Troubleshooting

If you encounter issues:

1. Check the error report for specific problems
2. Verify your file format and data
3. Ensure all required fields are present
4. Try importing a smaller batch to test


# Update Pass Using Flat Files

The Wallet Crew can update existing Apple Wallet and Google Wallet passes from a CSV file. This is useful for bulk updates and for legacy systems that can only export flat files.

{% hint style="warning" %}
SFTP imports are an optional feature. Ask The Wallet Crew to enable SFTP on your tenant before implementing this flow.

Treat SFTP imports as a **last resort**. Avoid this flow unless you have no other option (for example, a legacy system that can only export flat files).

For most projects, the API is the recommended approach. It is easier to automate, easier to monitor, and updates in real time.

If you prefer a real-time integration, use the [API update flow](/developers-guides/integration-guides/wallet/pass-lifecycle).
{% endhint %}

<details>

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

* A gift card program recalculates balance every hour. A flat file export updates `additionalData.balance` for all active cards.
* A marketing automation team exports a CSV to prepare a push campaign. Each row updates `additionalData.notification_content` before sending notifications.
* A ticketing system exports last-minute changes (gate, seat, or schedule). A bulk CSV update keeps tickets accurate right before doors open.
* A gym chain exports membership status every night (active, frozen, expired). The next day, members see the correct status at check-in.
* A support team fixes a wrong identifier at scale by uploading a one-time correction file.

</details>

<div data-with-frame="true"><figure><img src="/files/Sj7jkzdZKmsyCA2bUrhy" alt="Diagram showing a CSV file uploaded to SFTP, then processed by The Wallet Crew to update passes."><figcaption><p>Flat file imports let you update many passes in one operation.</p></figcaption></figure></div>

## Process overview

1. Upload your CSV file to the provided SFTP server.
2. The Wallet Crew automatically detects new files and processes them immediately.
3. Once processed, the file is moved to `.processed/` or `.error/`.
4. Each row is interpreted as an update instruction for a single pass.
5. Passes are queued for update and processed asynchronously.

## File format

Uploaded files must be valid [RFC 4180](https://www.ietf.org/rfc/rfc4180.txt){target="\_blank"} compliant CSV files.

* **Separators**: Either `,` or `;`
* **Header row**: Mandatory. Must contain column names.
* **Encoding**: UTF-8 recommended
* **Parser**: The Wallet Crew uses [CsvHelper](https://joshclose.github.io/CsvHelper/){target="\_blank"} with default options

Each data row targets a single pass and can include multiple updates to its fields, additionalData, or metadata.

## File name

There are no strict file name requirements. However, for better organization and traceability, we recommend the following naming convention:

```
<source>-passes-<YYYYMMDD>-<HHMMSS>.csv
```

Examples:

```
crm-passes-20250801-083000.csv 
loyalty-passes-20250731-235959.csv
```

Notes:

* The file extension must be `.csv`.
* Avoid using special characters (spaces, #, %, &, etc.) in file names
* If you are using a script or integration to generate files, adopting a timestamp-based naming pattern helps avoid duplication and makes debugging easier.
* If the file is large, The Wallet Crew briefly monitors its size to ensure it is fully written before processing.

## Column reference

### Pass identifier columns

To select the target pass, use one of the following columns:

* `id`: Internal The Wallet Crew pass identifier
* `id.<externalId>`: External identifier name (as configured in your tenant)\
  Example: `id.y2.customerId`

At least one identifier column must be present in each row.

### Additional data columns

To update additional data on the pass, use the following syntax:

* `additionalData.<key>`: Updates the key in the pass’s `additionalData` dictionary\
  Example: `additionalData.notification_content`

Multiple additionalData keys can be updated in one row.

### Pass template

To switch the pass to a different template, include:

* `passType`: The new template name (as defined in The Wallet Crew)

If omitted or empty, the pass will retain its current template.

### Metadata refresh

To trigger a recomputation of internal metadata (e.g., barcodes, expiration, display fields):

* `updateMetadata`: Set to `true` to trigger metadata update

### External identifiers

To update an external identifier, use the following syntax:

* `identifiers.<idName>`: Updates the identifier named `idName`\
  Example: `identifiers.y2.customerId`

## SFTP access

Upload your CSV files to the SFTP endpoint for your environment:

* **QA**: `triglav-qa.walletcrew.net` (port `22`)
* **Production**: `triglav.walletcrew.net` (port `22`)

Contact The Wallet Crew Support to request your SFTP credentials.

## Examples

### Example 1: Update Notification and Offer URL

```csv
id;additionalData.notification_content;additionalData.offer_url
Gk440DNzvfZcDmlA;Merry Christmas Alice!;https://acme.com/xmas1
HKlhrhrEXx2ZASYs;Merry Christmas Bob!;https://acme.com/xmas1
```

### Example 2: Update by External ID with Loyalty Info

```csv
id.y2.customerId;additionalData.notification_content
00100123;Enjoy 30% off on your next purchase
04503295;Thanks for your purchase! Only 10 points left to redeem a €10 voucher
02319202;Thanks for your purchase! Only 120 points left to redeem a €10 voucher
```

### Example 3: Switch Pass Template and Force Metadata Refresh

```csv
id;passType;updateMetadata
gH67xKlPzLZ99xa2;vip_template;true
dAk21jvUZYx39q77;standard_template;true
```

### Example 4: Update external id y2.customerId and force metadata refresh

```csv
id.y2.customerId;identifiers.y2.customerId;passType;updateMetadata
04503295;1010013295;;true
04503296;1010013296;;true
```

## Extensibility and custom mapping

The Wallet Crew supports custom file transformations using import scripts.

This allows you to:

* Adapt your existing export format (e.g., from a CRM or POS)
* Map legacy column names to The Wallet Crew-compatible keys
* Inject dynamic values (e.g., current date, calculated points)
* Enrich data with lookups from external sources

To customize the import process, you can create an `import.custom.js` file in the `scripts/` folder in Advanced configuration.

If you have the following CSV file:

```csv
id.y2.customerId,neo_notification_content,neo_offer_title,neo_offer_body
abc12345,"Hey Arthur !","Your 20% offer","20% Off for your next purchase"
```

You can use the following script:

```js
/**
 * Transforms a CSV row into an UpdatePassInformation-like object.
 *
 * @param {Object<string, string>} row - The CSV row, as a dictionary of column names to values.
 * @returns {Object} Transformed row information.
 * @returns {Object<string, string>} return.Identifiers - Identifiers for this row (e.g., customer ID).
 * @returns {string|null} return.PassType - The type of pass, or null if not present.
 * @returns {Object<string, string>} return.AdditionalData - Optional additional data from prefixed columns.
 */
function transform(row){
  const identifiers = {
      "id.y2.customerId" : row["id.y2.customerId"]
  };

  const passType = row.passType || null; 

  const properties = [
    "notification_content",
    "offer_title", 
    "offer_body"
   ];

  let additionalData = {};
  for(const property of properties){
    if(row["neo_" + property] !== undefined){
      additionalData[property] = row["neo_" + property].toString(); 
    }
  }

  return {
    Identifiers : identifiers, 
    PassType: passType,
    AdditionalData : additionalData
  }
}

/**
 * Optional method to return a custom throughput for a given import file.
 *
 * @param {string} fileName - The import file name.
 * @returns {number|null} Throughput override, or null to use default.
 */
function getThroughput(fileName) {
  // Example: return null to use default
  return null;
}

export default function(context) {
  context.register('runtime.import.updatePasses.rowTransformer', {
    Transform: transform, 
    GetThroughput: getThroughput
  });
}
```

Contact our team if you need help implementing custom mapping logic for your imports.

## Tips and best practices

* Ensure identifiers are accurate to avoid skipped rows.
* Always test your file format in QA before uploading to production.
* Use consistent encoding (UTF-8) to avoid parsing issues with special characters.

## FAQ

<details>

<summary><strong>Do you create new passes, or only update existing ones?</strong></summary>

This flow updates existing passes. Each row must target a pass using `id` or an external identifier column like `id.y2.customerId`.

</details>

<details>

<summary><strong>What happens if a row has both <code>id</code> and <code>id.&#x3C;externalId></code>?</strong></summary>

Use one identifier per row if you can. If you include several, make sure they all point to the same pass. This avoids ambiguity and makes troubleshooting easier.

</details>

<details>

<summary><strong>Can I update multiple <code>additionalData</code> keys in one row?</strong></summary>

Yes. Add one column per key, using `additionalData.<key>`. The row will update all provided keys in one pass update.

</details>


# Pass Migration

Use pass migration when you want to change the system that **manages** your passes, while keeping already-installed passes working for customers.

A migration is a “behind the scenes” change. Customers keep the same pass in Apple Wallet or Google Wallet. Your goal is continuity: the pass stays valid, and updates keep working.

{% hint style="success" %}
In most cases, you can migrate without impacting customers.

If you plan the switch and test first, customers keep the same pass and it keeps updating.
{% endhint %}

<details>

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

* A retail Brand migrates loyalty cards mid-season without asking customers to reinstall.
* A show organizer switches ticketing providers after a pilot.
* A Brand consolidates several pass providers into a single platform.

</details>

## What customers should experience ?

When a migration is done correctly, customers do not reinstall anything. They keep the same pass on their device, and they can continue using it as usual.

In practice, this means the barcode or QR code used in-store or at the gate stays the same. The pass also keeps receiving updates (for example : points, tier, balance, seat, gate, or validity).

Most migrations include a short pilot. You validate the flow with a small batch, then you cut over the remaining passes.

### Typical migration plan

The exact steps depend on the direction (to or away from The Wallet Crew) and the platform constraints. The flow below stays broadly true in most projects.

{% stepper %}
{% step %}

### 1) Confirm what “in-place” means for your setup

Confirm which Apple issuer identity signs your passes, and which Google Wallet issuer account owns them. This is what decides whether customers can keep the same pass, or whether you need a re-issuance flow.
{% endstep %}

{% step %}

### 2) Export pass technical identifiers

You need the identifiers that let the new system attach to the existing passes (for example Apple serial numbers + authentication tokens, or Google resource IDs/object IDs).
{% endstep %}

{% step %}

### 3) Map fields and run a pilot batch

Run a small batch first. Update a visible field and validate it on real devices. Keep the pilot simple so you can iterate fast.
{% endstep %}

{% step %}

### 4) Cut over, then monitor

Execute the cutover plan, then monitor updates and redemption for a few days. Keep a rollback option if your previous provider supports it.
{% endstep %}
{% endstepper %}

### Coordination and timeline

A migration requires coordination between parties. It is usually your current provider and The Wallet Crew, with your own team involved when you control issuer accounts and certificates.

The work is rarely “hard” technically. Most of the time is spent aligning on export format, field mapping, security approvals, and the cutover plan. Plan a few weeks for a typical project. Timelines vary by provider and approval cycles.

### Choose your path

* Moving **to** The Wallet Crew: [Move passes to The Wallet Crew](/configure/advanced-configuration/wallet/import-and-export/pass-migration/move-passes-to-the-wallet-crew)
* Moving **away** from The Wallet Crew: [Export passes from The Wallet Crew to another provider](/configure/advanced-configuration/wallet/import-and-export/pass-migration/export-passes-from-twc-to-another-provider)

### Key constraints (Apple vs Google)

Apple Wallet and Google Wallet have different rules. These rules explain why migrations require coordination and why a test batch matters.

#### Apple Wallet

Apple Wallet migrations depend on the issuer identity used to sign passes. They also depend on the update “address” embedded in the pass (`webServiceURL`), because devices call that URL to fetch updates.

If you can keep the same issuer identity and correctly repoint `webServiceURL`, customers can usually keep the same installed pass.

#### Google Wallet

Google Wallet migrations depend on which issuer account owns the passes. If the issuer account changes, you usually need to re-issue passes (which implies a new save flow for customers).

If you keep the same issuer account and object IDs, customers can usually keep the same pass.

### FAQ

<details>

<summary><strong>Do customers need to reinstall their pass during a migration?</strong></summary>

Usually no. If you migrate “in place” (same Apple issuer identity, and Google under the same issuer account), customers keep the same pass and it keeps updating.

</details>

<details>

<summary><strong>What data do we usually need from the previous provider?</strong></summary>

You usually need technical identifiers that let a new system attach to the existing pass.

* For Apple, it’s typically the serial number and authentication token.
* For Google, it’s typically the resource ID (object ID).

</details>

<details>

<summary><strong>How long does a migration usually take?</strong></summary>

Plan a few weeks. Most of the time is coordination, not implementation. You need time for export, mapping, and a small test batch.

</details>

<details>

<summary><strong>Who needs to be involved?</strong></summary>

You need your current provider and The Wallet Crew. If you control issuer accounts and certificates, your team is involved too.

</details>


# Move Passes to The Wallet Crew

Migrate active Apple Wallet and Google Wallet passes from another provider into The Wallet Crew without forcing customers to reinstall.

Use this guide when you want to move **already-installed** Apple Wallet and Google Wallet passes from another provider to The Wallet Crew.

The goal is continuity for customers. When the migration is done correctly, they keep the same pass on their device, they do not reinstall anything, and your barcode and redemption flow stay unchanged.

Most of the work is coordination, not implementation. You align issuer credentials, export the technical identifiers that tie each pass to its existing Apple/Google record, validate with a small pilot, then run a controlled cutover.

If you need the reverse flow, see [Export passes from The Wallet Crew to another provider](/configure/advanced-configuration/wallet/import-and-export/pass-migration/export-passes-from-twc-to-another-provider).

<details>

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

* A Brand decides to change wallet pass provider, but wants customers to keep their installed passes.
* A Brand replaces an in-house wallet setup with The Wallet Crew to get a more reliable operating layer.
* A Brand changes an underlying system (CRM, loyalty, ticketing, POS) and needs to transfer active passes safely.

</details>

## Before you start

Most migrations succeed or fail based on platform constraints and who controls issuer credentials.

If you want background on identifiers and pass data, read [Structure.](/developers-guides/pass-architecture/structure)

### Set up your The Wallet Crew project before migrating

You cannot start a migration before your The Wallet Crew project is already working end-to-end.

Migration is not “creating passes again”. It is importing the identifiers that let The Wallet Crew take over updates for passes that are already installed on devices. If your project is not configured, imported passes will exist, but they will not update reliably after cutover.

Before you import anything, make sure:

* You have connected the wallet providers and can sign/own passes (Apple Pass Type ID and certificates, Google Wallet issuer account access).
* You have decided which **external identifiers** you will use to link passes to your systems (customer ID, ticket ID, membership number, order ID, ...). These must be stable over time.
* You can compute pass content from your source of truth (API integration, file workflow, or operational process).
* You can run a full lifecycle on test passes: issue, update a visible field, and verify the update on a real device.

<details>

<summary>Migration readiness checklist</summary>

Use this as a go/no-go list before you touch production passes.

* [ ] You know which Apple Pass Type ID signs the existing passes.
* [ ] You have the Apple credentials needed to keep the same issuer identity.
* [ ] You know the Google Wallet `issuerId` that owns the existing passes.
* [ ] You have access to that issuer account in the Google Pay & Wallet Console.
* [ ] Your current provider can export one row per pass with required identifiers.
* [ ] Your current provider can send an Apple “final update” (see cutover step).
* [ ] You have a pilot batch of 2–3 real passes per platform.
* [ ] You have a rollback plan for Apple (if supported by the old provider).

{% hint style="info" %}
Plan for at least one pilot cycle. Most delays come from exports, approvals, and cutover scheduling.
{% endhint %}

</details>

{% hint style="info" %}
Plan for at least one pilot cycle. Most delays come from exports, approvals, and cutover scheduling.
{% endhint %}

### What you import: pass identifiers (platform + external)

You do not recreate passes during a migration. You import identifiers so The Wallet Crew can update passes that are **already installed** on devices.

You import two kinds of identifiers:

* **Platform identifiers**. These point to the existing Apple/Google pass record.
  * Apple: `serialNumber` + `authenticationToken`
  * Google: object **resource ID** (often called object ID)
* **External identifiers**. These link a pass back to your own systems.
  * Examples: customer ID, ticket ID, membership number, order ID

Platform identifiers let The Wallet Crew update the same pass on the device. External identifiers let you match the pass to the right customer record and keep updates correct after cutover.

A single pass can have multiple external identifiers. This is useful when you reconcile data across systems.

### Decide if you can migrate “in place”

Apple and Google do not allow the same migration patterns.

#### Apple Wallet (in-place is usually possible)

You can usually migrate without reinstall if you keep the same Apple issuer identity (same Pass Type ID / signing identity) and you repoint the pass update endpoint (`webServiceURL`).

This typically requires your current provider to send at least one “final update” to installed passes. That update embeds The Wallet Crew `webServiceURL` so devices start calling The Wallet Crew for future updates.

#### Google Wallet (only if you keep the same issuer account)

Google Wallet passes are tied to a Google Pay & Wallet Console issuer account (`issuerId`).

If the existing passes were created under an issuer account you do not control, you cannot transfer them in place. You must plan a re-issuance flow (new save links, new objects).

{% hint style="warning" %}
For Google Wallet, plan the migration around your issuer account.

If your current provider issued passes under an issuer account you do not control, plan a re-issuance flow.
{% endhint %}

### What you need from your current provider

Ask for one export row per pass. You will use it to attach The Wallet Crew to the *existing* installed pass.

At minimum, get:

* **Apple Wallet**: `serialNumber` and `authenticationToken`
* **Google Wallet**: object **resource ID** (often called “resource ID” or “object ID”)
* A stable customer identifier (email, customer ID, ticket ID). This is how you match passes back to customers.

{% hint style="info" %}
If your current provider can also share the Apple Pass Type ID and the Google `issuerId`, it speeds up the eligibility check.
{% endhint %}

## Migration steps

### Sequence overview (what happens end-to-end)

These diagrams show the control points you need for a clean cutover. The key idea is simple: you import identifiers into The Wallet Crew, then you make sure devices start fetching updates from The Wallet Crew.

{% tabs %}
{% tab title="Apple Wallet" %}
Apple in-place migration usually works if you keep the same Pass Type ID and your current provider can ship a “final update” that changes the pass `webServiceURL` to The Wallet Crew.

```mermaid
sequenceDiagram
  autonumber
  participant Brand as Brand systems
  participant Old as Old provider
  participant TWC as The Wallet Crew
  participant Device as Customer device (Apple Wallet)

  Brand->>Old: Request export (serialNumber, authenticationToken, external IDs)
  Old-->>Brand: Export file / feed
  Brand->>TWC: Import identifiers

  Brand->>Old: Ask for "final update" setting webServiceURL = The Wallet Crew
  Old->>Device: Push update notification
  Device->>Old: Fetch updated pass package
  Old-->>Device: Pass updated with new webServiceURL

  Brand->>TWC: Update pass data after cutover
  TWC->>Device: Push update notification
  Device->>TWC: Fetch updated pass package
  TWC-->>Device: Updated pass content
```

{% endtab %}

{% tab title="Google Wallet" %}
Google in-place migration works only if the existing passes belong to an `issuerId` you control. In that case, The Wallet Crew updates the same object resource IDs.

```mermaid
sequenceDiagram
  autonumber
  participant Brand as Brand systems
  participant Old as Old provider
  participant TWC as The Wallet Crew
  participant Google as Google Wallet
  participant Device as Customer device (Google Wallet)

  Brand->>Old: Request export (object resource ID, external IDs)
  Old-->>Brand: Export file / feed
  Brand->>TWC: Import identifiers (resource IDs)

  Brand->>TWC: Update pass data after cutover
  TWC->>Google: Update existing object (same issuerId)
  Google-->>Device: Customer sees updated pass content after sync
```

{% endtab %}
{% endtabs %}

{% stepper %}
{% step %}

### Configure The Wallet Crew issuer credentials

You need The Wallet Crew to authenticate as the same “issuer” as the existing passes.

* For Apple, use the same Pass Type ID as your current provider whenever possible. Then configure certificates.\
  Follow: [Apple Wallet certificates](/configure/advanced-configuration/wallet/apple-and-google-wallet/apple-wallet-certificates).
* For Google, confirm which Google Wallet issuer account owns the existing passes. You need access to that issuer account.\
  Follow: [Google Wallet account](/configure/advanced-configuration/wallet/apple-and-google-wallet/google-wallet-account).
  {% endstep %}

{% step %}

### Export pass technical identifiers from your current provider

Ask your current provider for one export row per pass.

At minimum, export:

* Apple: **serial number** and **authentication token**
* Google: **resource ID** (or object ID)
* Your external identifiers (so you can match each pass to the right customer)
  {% endstep %}

{% step %}

### Import those passes into The Wallet Crew

Import the exported identifiers into The Wallet Crew so each pass record can be linked to its existing Apple/Google identifiers.

Start with [Import & Export](/configure/advanced-configuration/wallet/import-and-export). If you need a file-based bulk update flow, see [Update pass using flat files](/configure/advanced-configuration/wallet/import-and-export/update-pass-using-flat-files).

{% hint style="info" %}
Migration imports often require extra columns (Apple auth token, Google resource ID).

If you don’t see how to map those fields in your tenant, ask The Wallet Crew team to confirm the expected file format.
{% endhint %}
{% endstep %}

{% step %}

### Cut over: repoint Apple pass updates to The Wallet Crew

Apple Wallet passes fetch updates from the `webServiceURL` embedded in the pass.

To migrate without reinstall, your current provider must update `webServiceURL` on the existing passes and trigger an update so devices download the new pass version.

{% hint style="warning" %}
Do not shut down your previous provider’s Apple web service until you have validated cutover on real devices.

If the old endpoint stops responding before devices receive the “final update”, passes may stop updating.
{% endhint %}

Ask your old provider to bulk update all existing passes so their `webServiceURL` matches The Wallet Crew `webServiceURL` :

> `https://api-passd.neostore.cloud/api/<tenantId>/passes/apple`

replace `<tenantId>` by your tenantId, confirm the value with The Wallet Crew support team.
{% endstep %}

{% step %}

### Validate on a small sample

Pick 2–3 passes on each platform.

Update a visible field through The Wallet Crew. Then verify it updates on devices.

If you need to accelerate refresh during testing, run a push update from The Wallet Crew. This is useful on both platforms: Apple devices fetch the updated pass package, and Google users see the updated object sooner.
{% endstep %}

{% step %}

### Monitor after cutover

Monitor updates and redemption for a few days. Keep a rollback option if your previous provider supports it.

For Apple, rollback usually means switching `webServiceURL` back and triggering an update. Do not attempt this unless you have a confirmed working endpoint on the old provider.
{% endstep %}
{% endstepper %}

## Common pitfalls

Apple and Google failures look different. These checks catch most issues early.

### Apple Wallet

If customers report that passes stop updating after cutover, it is usually one of these:

* The `webServiceURL` was not updated on the installed passes.
* The old provider updated `webServiceURL` but did not trigger a push update.
* The Wallet Crew Apple credentials do not match the original pass identity (Pass Type ID / certificate).

### Google Wallet

If updates fail on Google, it is usually one of these:

* The existing passes belong to a different `issuerId`.
* The exported “resource ID” does not match the object IDs being updated.
* The Google Pay & Wallet Console permissions do not allow updates from The Wallet Crew credentials.

## FAQ

<details>

<summary><strong>Do customers need to reinstall their pass?</strong></summary>

Usually no.

If you repoint the Apple `webServiceURL` correctly, existing passes keep updating in place.

For Google, if you keep the same issuer account and resource IDs, users typically keep the same pass.

</details>

<details>

<summary><strong>Why do we need the Apple authentication token?</strong></summary>

Apple uses the authentication token to authenticate update requests for a given serial number.

Without it, a new provider cannot reliably serve updates to the same installed pass.

</details>

<details>

<summary><strong>Can we migrate Google Wallet passes between issuer accounts?</strong></summary>

Not in-place.

Google Wallet passes are tied to the issuer account. If the issuer changes, plan a re-issuance flow.

</details>

<details>

<summary><strong>How do we know the Apple cutover worked?</strong></summary>

Update a visible field in The Wallet Crew and confirm the change on a real device. If you can, also confirm the installed pass is calling The Wallet Crew endpoint by checking server logs or by asking The Wallet Crew Support to confirm traffic.

</details>

<details>

<summary><strong>What if we can’t keep the same Apple Pass Type ID?</strong></summary>

Plan for re-issuance.

If the Apple issuer identity changes, customers usually need to add a new pass. Run a controlled rollout and keep the old pass valid for a transition period when possible.

</details>

<details>

<summary><strong>What if our current provider can’t send the Apple “final update”?</strong></summary>

You may not be able to migrate Apple passes in place.

Without a final update, installed passes keep calling the old `webServiceURL`. In that case, you must either keep the old endpoint running, or plan a re-issuance flow.

</details>

<details>

<summary><strong>Do we need to change barcodes or redemption logic?</strong></summary>

Not necessarily.

If you keep the same pass identifiers and you keep generating the same barcode payload, your in-store or gate scanning flow can stay unchanged. Validate this explicitly during the pilot by scanning migrated passes in real conditions.

</details>

<details>

<summary><strong>What should we communicate to customers during the migration?</strong></summary>

If the migration is in-place, you usually don’t need to communicate anything. Customers keep the same pass and it keeps updating.

If you must re-issue passes, communicate the new “Add to Wallet” flow clearly and early. Keep it short and focus on what customers need to do.

</details>


# Export Passes From TWC to Another Provider

Export your Apple Wallet and Google Wallet passes so a new provider can take over updates, with clear constraints for each platform.

If you ever decide to stop using The Wallet Crew, you can do it anytime. This page explains how to migrate without breaking pass updates for customers.

This is also why we ask Brands to use their own Apple and Google Wallet accounts. It keeps you as the issuer of record. It also prevents vendor lock-in.

Your customer data is yours. You stay the data controller. In practice, your source of truth stays in your CRM and internal systems.

To switch providers, you export the operational pass identifiers from The Wallet Crew. You give them to your new provider so they can take over updates.

{% hint style="info" %}
If you’re considering leaving because of a blocker, tell us early. We can often fix it without requiring a migration.
{% endhint %}

Apple Wallet and Google Wallet do not behave the same. Apple passes fetch updates from a `webServiceURL`. Google passes are tied to a Google Wallet issuer account.

## What you need to plan (Apple vs Google)

### Apple Wallet

Apple passes installed on devices keep calling the `webServiceURL` embedded in the pass.

To move to a new provider, you need to:

1. Export each pass **serial number** and **authentication token**.
2. Update the `webServiceURL` to your new provider endpoint.
3. Trigger an update so devices download a pass version pointing to the new provider.

### Google Wallet

Google Wallet passes are tied to a **Google Wallet issuer account**.

You cannot "transfer" passes to a different issuer account. Your new provider must either:

* operate under the **same** issuer account, or
* re-issue passes under a new issuer account (new save links, new objects).

## Step-by-step

{% stepper %}
{% step %}

### Export pass data from The Wallet Crew

Open the passes list in the admin console:

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/passes/" class="button secondary" data-icon="chevrons-right">The Wallet Crew Administration Console - Pass List</a></p>

Export the full list.

Make sure the export includes, at minimum:

* Apple: **serial number** and **authentication token**
* Google: **resource ID** (or object ID)
* Your external identifiers (so the new provider can map passes back to customers)
  {% endstep %}

{% step %}

### Give the export to your new provider

Send the exported file to your new provider. They need it to attach to existing passes.

For Apple, they will typically import serial + auth token to be able to sign and serve updates.

For Google, they will typically use resource IDs to update the existing objects.
{% endstep %}

{% step %}

### Switch Apple passes to the new update endpoint

Agree on the new Apple Wallet web service endpoint with your new provider.

Then ask The Wallet Crew team to:

1. configure the target `webServiceURL` for your tenant, and
2. run a bulk "push update" so installed passes pick up the new URL.

{% hint style="warning" %}
If you switch the `webServiceURL` without a working endpoint on the new provider, Apple passes may stop updating.

Plan a short validation window and test on a small sample first.
{% endhint %}
{% endstep %}

{% step %}

### Validate the migration

Pick 2–3 test passes (Apple and Google).

Ask the new provider to:

* update a visible field (example: points balance, status, or event gate)
* confirm the update is visible on devices within a few minutes

For Apple, also confirm that updates still work after reinstalling the pass.
{% endstep %}
{% endstepper %}

## FAQ

<details>

<summary><strong>Do end-users need to reinstall their pass?</strong></summary>

Usually no.

If you switch Apple `webServiceURL` correctly, existing passes keep updating without reinstall.

For Google, if you keep the same issuer account and object IDs, users typically keep the same pass.

</details>

<details>

<summary><strong>Can we move Google Wallet passes to a different issuer account?</strong></summary>

Not in-place.

Google Wallet passes are tied to the issuer account. If the issuer changes, plan a re-issuance flow.

</details>

<details>

<summary><strong>What’s the minimum data we must export?</strong></summary>

For Apple, you need the serial number and authentication token.

For Google, you need the resource ID.

External identifiers are strongly recommended. They let the new provider keep pass-to-customer mapping.

</details>


# Advanced configuration

Advanced tenant configuration for power users: manage YAML files, \`.fctwc\` backups, audit history, and configuration comparisons with The Wallet Crew Support guidance.

Advanced configuration provides power-user access to The Wallet Crew tenant YAML configuration. Each tenant has a set of YAML files that define its complete configuration.

Secrets are not stored in these files. The Wallet Crew stores secrets in a dedicated Key Vault.

The **Advanced configuration** editor is intended for power users. It provides controlled access for support-directed exceptions, full configuration backups, imports, and change review.

{% hint style="warning" %}
Do not use this editor unless The Wallet Crew Support team asks for a specific change. Most settings have dedicated screens that update the underlying files safely.
{% endhint %}

<details>

<summary>Real-world examples</summary>

* The Wallet Crew Support team provides a configuration adjustment for an exceptional connector requirement.
* A power user exports an `.fctwc` backup before a support-guided configuration update.
* A team compares staging and production configuration before an approved release.

</details>

### Open the advanced configuration editor

Open the tenant's advanced configuration editor from **Settings** → **Advanced configuration**.

Use the editor only after receiving instructions from The Wallet Crew Support team. Do not change a configuration file without those instructions. A file can affect several platform features.

### Export or import a full tenant configuration

The editor can export the full tenant configuration as a backup. The exported file uses the `.fctwc` extension, which means **Full Configuration The Wallet Crew**.

An `.fctwc` file is a ZIP archive containing all tenant configuration files. Keep exports securely, as they can contain configuration details.

Use import to restore or transfer a previously exported tenant configuration:

1. Export the current configuration before making changes.
2. Select the `.fctwc` file to import.
3. Review the imported configuration, then validate its effect in the relevant administration screens.

{% hint style="info" %}
An import restores configuration files only. Secrets remain managed separately in the dedicated Key Vault.
{% endhint %}

### Review tenant configuration changes

The configuration audit history records tenant configuration changes. Open **Settings** → **Monitoring** → **Audit** to review them.

The history table shows four columns:

* **Timestamp** — when the change occurred.
* **File name** — the configuration file that changed.
* **Author** — the person who made the change.
* **File changes** — the recorded modification.

Each entry provides two comparison actions:

* **Compare with previous** shows the selected version against its preceding version.
* **Compare with current** shows the selected version against the active configuration.

### Compare tenant configurations

Open **Settings** → **Tools** → **Configuration comparison** to compare tenant configurations without changing them.

This view can compare configurations across environments. It can also compare tenants when access includes more than one tenant. Select a date to compare the active configuration with a previous version.

Use comparisons before importing a backup or applying an exceptional manual change. This helps identify unintended differences early.

### Configuration file reference

Each configuration file has a dedicated reference page. These pages describe the file's purpose, supported YAML schema, and configuration constraints.

### FAQ

<details>

<summary>When should the advanced configuration editor be used?</summary>

Use it only when The Wallet Crew Support team requests a specific change. Standard platform features should be configured through their dedicated administration screens.

</details>

<details>

<summary>Does a full configuration export include secrets?</summary>

No. Secrets are stored separately in the dedicated Key Vault and are not included in `.fctwc` exports.

</details>

<details>

<summary>Can configurations be compared across tenants?</summary>

Yes, when the account has access to more than one tenant. The comparison view also supports environment and date-based comparisons.

</details>


# Wallet pass connectors

Explore The Wallet Crew connectors for CRM, loyalty, ticketing, e-commerce, POS, and marketing platforms that create, update, and distribute Apple Wallet and Google Wallet passes.

Wallet pass connectors link existing business systems to Apple Wallet and Google Wallet passes managed by The Wallet Crew. They support CRM, loyalty, ticketing, e-commerce, point-of-sale, marketing automation, email, and hardware integrations.

Connectors are integration accelerators, not plug-and-play solutions. Each integration reflects its data model, business rules, and operating processes. A connector can include sync logic, configuration tooling, file exchange support, and implementation guidance.

The brand or partner system remains the source of truth for business data. The Wallet Crew does not replace or duplicate it. The platform transforms source data into wallet-compatible content and can send wallet analytics back to connected systems.

### What a wallet pass connector provides

* Create and update Apple Wallet and Google Wallet pass content from source data.
* Deliver wallet lifecycle events and analytics to connected business systems.
* Support standard connectors or custom integrations for private APIs and workflows.

## Integrate software without a listed connector

You can still integrate with The Wallet Crew even when no native connector exists.

Use this sequence:

1. Start from the integration model and identify where your source data lives.
2. Decide whether a built-in connector is enough or a custom connector is needed.
3. Implement runtime scripting only for the parts that are truly specific to your stack.

### Main integration model

The integration model stays the same for all projects:

1. Your system remains the source of truth for business data.
2. TWC stores identifiers and wallet-facing operational data.
3. TWC reads and transforms source data into Apple Wallet and Google Wallet payloads.
4. Wallet lifecycle events and analytics can be pushed back to your systems.

This model avoids data duplication while keeping wallet experiences up to date.

### Choose your integration path

| Situation                                                                                                        | Recommended path                                             |
| ---------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ |
| Your software already has a documented connector                                                                 | Use the connector page in this section                       |
| Your software has no connector, but your APIs and events are available                                           | Use [Custom connector](/connectors/custom-connector)         |
| Your integration mostly needs runtime behavior (data fill hooks, install/uninstall hooks, script email delivery) | Start with [Custom connector](/connectors/custom-connector). |

### Responsibilities

| Responsibility area            | Customer / partner system                        | The Wallet Crew                                  |
| ------------------------------ | ------------------------------------------------ | ------------------------------------------------ |
| Business data ownership        | Owns CRM/POS/ticketing/e-commerce records        | Does not replace source systems                  |
| Identifier strategy            | Defines stable identifiers shared across systems | Uses identifiers to resolve and update pass data |
| Wallet payload generation      | Provides source fields and business rules        | Maps data to Apple/Google wallet formats         |
| Pass delivery and updates      | Triggers source events and change inputs         | Orchestrates wallet updates and pass lifecycle   |
| Optional integration scripting | Implements project-specific API/event logic      | Provides runtime hooks and execution context     |

The cards below cover each connector family.

## Wallet pass connector categories

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-cover data-type="image">Cover image</th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><h4>CRM &#x26; fidelity</h4></td><td>Connect CRM and loyalty systems to Apple Wallet and Google Wallet passes.</td><td><a href="/files/ZAiN5M6Xaq0GAG5BQ3LU">/files/ZAiN5M6Xaq0GAG5BQ3LU</a></td><td><a href="/spaces/lP7d71aYydav6e0pRkxc/pages/0UJ2xkOumdHXTbL5s2lZ">/spaces/lP7d71aYydav6e0pRkxc/pages/0UJ2xkOumdHXTbL5s2lZ</a></td></tr><tr><td><h4>Custom connector</h4></td><td>Build a custom integration when a ready-to-use connector is not available.</td><td><a href="/files/2c4PExuPQTteoa7W2Klw">/files/2c4PExuPQTteoa7W2Klw</a></td><td><a href="/spaces/lP7d71aYydav6e0pRkxc/pages/csbAvidL0x1vBJvTfNIs">/spaces/lP7d71aYydav6e0pRkxc/pages/csbAvidL0x1vBJvTfNIs</a></td></tr><tr><td><h4>E-commerce</h4></td><td>Connect storefront journeys to wallet pass distribution and in-store usage.</td><td><a href="/files/SqI4ch2W1tB87PhSeHmt">/files/SqI4ch2W1tB87PhSeHmt</a></td><td><a href="/spaces/lP7d71aYydav6e0pRkxc/pages/8ufnC6LGq6X3S3Cprqpv">/spaces/lP7d71aYydav6e0pRkxc/pages/8ufnC6LGq6X3S3Cprqpv</a></td></tr><tr><td><h4>Email provider</h4></td><td>Configure how The Wallet Crew sends transactional wallet emails.</td><td><a href="/files/o3MS4svn8uEvpPGAfOBB">/files/o3MS4svn8uEvpPGAfOBB</a></td><td><a href="/spaces/lP7d71aYydav6e0pRkxc/pages/6ceaERWySMiMhWfbbd1h">/spaces/lP7d71aYydav6e0pRkxc/pages/6ceaERWySMiMhWfbbd1h</a></td></tr><tr><td><h4>Hardware</h4></td><td>Check hardware compatibility for barcode, QR, and NFC wallet validation.</td><td><a href="/files/PrZbfmfVt41LrU0LniP8">/files/PrZbfmfVt41LrU0LniP8</a></td><td><a href="/spaces/lP7d71aYydav6e0pRkxc/pages/ZUepDuWx3VxyC0pYwr2i">/spaces/lP7d71aYydav6e0pRkxc/pages/ZUepDuWx3VxyC0pYwr2i</a></td></tr><tr><td><h4>Marketing automation</h4></td><td>Connect lifecycle campaigns and wallet pass updates in existing tools.</td><td><a href="/files/avW0zc3JyRKN8EoxpyAb">/files/avW0zc3JyRKN8EoxpyAb</a></td><td><a href="/spaces/lP7d71aYydav6e0pRkxc/pages/h2frQtSx2WuPBGcUQECD">/spaces/lP7d71aYydav6e0pRkxc/pages/h2frQtSx2WuPBGcUQECD</a></td></tr><tr><td><h4>POS</h4></td><td>Connect point-of-sale systems to wallet passes for identification and redemption.</td><td><a href="/files/2MXFoQQ2PR4Vl0PT2abL">/files/2MXFoQQ2PR4Vl0PT2abL</a></td><td><a href="/spaces/lP7d71aYydav6e0pRkxc/pages/lmRaIhnUEqOj9W6tbwUc">/spaces/lP7d71aYydav6e0pRkxc/pages/lmRaIhnUEqOj9W6tbwUc</a></td></tr><tr><td><h4>Ticketing</h4></td><td>Distribute and update event tickets in Apple Wallet and Google Wallet.</td><td><a href="/files/1luwSBCnAkrqlFpeo5YT">/files/1luwSBCnAkrqlFpeo5YT</a></td><td><a href="/spaces/lP7d71aYydav6e0pRkxc/pages/cENxsYXrqOhPDdZhM5Kd">/spaces/lP7d71aYydav6e0pRkxc/pages/cENxsYXrqOhPDdZhM5Kd</a></td></tr></tbody></table>


# Email provider

Choose how The Wallet Crew sends transactional emails through SendGrid, a supported provider, or a custom email connector.

The Wallet Crew can send transactional emails as part of your customer journey. These emails are sent **on behalf of your Brand**, so customers recognize the sender and trust the message.

This matters for conversion and security. A branded, authenticated sender reduces phishing risk. It also increases confidence when customers click an “Add to Wallet” link.

<figure><img src="/files/RATslsCj2luZDPAa9g1y" alt="Example transactional email containing an Add to Wallet link"><figcaption><p>Transactional emails can distribute a pass or support enrolment and verification flows.</p></figcaption></figure>

## What emails The Wallet Crew can send

Email sending depends on the journey you enable. Common examples include pass distribution and enrolment flows.

* A link to download a customer loyalty card in Apple & Google Wallet.
* A registration email when a customer enrols through a form.
* A challenge email to authenticate a customer (verification code or link).
* A confirmation email after registration or verification.

## Why you should configure the sender identity

When your emails use a sender identity that matches your Brand, customers are less likely to distrust the message. When the sender is properly authenticated (SPF, DKIM, DMARC), mailbox providers are less likely to flag the email as spoofing.

In practice, this improves deliverability and reduces phishing opportunities around “download your pass” links.

{% hint style="info" %}
If you want customers to see `no-reply@yourbrand.com` (or `no-reply@wallet.yourbrand.com`), plan SPF/DKIM and a DMARC policy. This is what mailbox providers use to validate the sender.
{% endhint %}

## Choose your email provider strategy

The Wallet Crew uses **SendGrid** by default. You can keep this default, switch to another supported provider, or plug your own gateway.

### Default: SendGrid

This is the fastest option. It covers most use cases. See [SendGrid](/connectors/email-provider/sendgrid) for supported modes and configuration.

Even with SendGrid, use a custom sending domain that matches the Brand. Confirm the required SPF, DKIM, and DMARC records during implementation.

### Built-in connectors

Use this when your Brand already has a provider, templates, reporting, or compliance processes in place.

Supported built-in connectors:

* [Adobe Marketing Cloud](/connectors/email-provider/adobe-marketing-cloud)
* [Mailchimp](/connectors/email-provider/mailchimp)
* [Salesforce Marketing Cloud](/connectors/email-provider/salesforce-marketing-cloud)
* [SendGrid](/connectors/email-provider/sendgrid)

### Custom connector

Use this when you need a provider that is not supported by built-in connectors, when you must route through an internal mail relay, or when you want to fully control sending from your backend.

The Wallet Crew still renders the email content. Your implementation is responsible for the final “send” call and its delivery lifecycle.

* [EmailSender extensibility](/connectors/custom-connector/emailsender-extensibility)

### Email providers not listed

An unlisted provider does not prevent wallet email delivery. The Wallet Crew and the provider partner can jointly scope a standard connector when the integration can support multiple Brands.

For a provider specific to one tenant, use a custom connector. Tenant scripting calls the provider API or internal relay through [EmailSender extensibility](/connectors/custom-connector/emailsender-extensibility).

## Where the configuration lives

The active email provider is selected in `/server/emails.yml` in the advanced configuration. Each connector page tells you exactly what values to set for its provider type.

## FAQ

<details>

<summary><strong>Are these marketing emails?</strong></summary>

No. These are transactional emails tied to a customer journey, like pass download links or verification messages.

If you want marketing campaigns, use your marketing tools. Then embed The Wallet Crew links in their templates.

</details>

<details>

<summary><strong>Can The Wallet Crew send from our domain?</strong></summary>

Yes, as long as the sender domain is properly authenticated. For SendGrid, this typically means configuring SPF/DKIM and a DMARC policy for the domain (or subdomain) you use as the sender.

</details>

<details>

<summary><strong>What is the quickest way to reduce phishing risk?</strong></summary>

Use a sending domain aligned with your Brand and enforce DMARC. Avoid generic sender domains that customers do not recognize.

</details>

<details>

<summary><strong>When should we use the EmailSender extensibility?</strong></summary>

Use it when you need a provider that is not supported by connectors, when you must route through an internal mail gateway, or when you want to centralize sending logic in your own systems.

</details>

<details>

<summary><strong>What if our email provider is not listed?</strong></summary>

The Wallet Crew and the provider partner can scope a standard connector. A tenant-specific provider can also use a custom connector with tenant scripting and the provider API.

</details>


# Adobe Marketing Cloud

Send The Wallet Crew transactional emails via Adobe Journey Optimizer, Adobe Campaign, or Marketo Engage using the script email provider.

Use this integration when you want The Wallet Crew to send **transactional emails** through an **Adobe marketing product** your Brand already uses.

“Adobe Marketing Cloud” is not a single email product. Email sending depends on what you run in Adobe:

* [Adobe Journey Optimizer (AJO)](/connectors/email-provider/adobe-marketing-cloud/adobe-journey-optimizer) for API-triggered journeys and near real-time sends.
* [Adobe Campaign Transactional Messaging](/connectors/email-provider/adobe-marketing-cloud/adobe-campaign-transactional-messaging) for transactional messaging events in legacy Adobe stacks.
* [Marketo Engage (Transactional Email API)](/connectors/email-provider/adobe-marketing-cloud/marketo-engage-transactional-email-api) for transactional email sends tied to Marketo templates.

This is a **script-based** connector. The Wallet Crew still renders email content if you want it to. Your script then delegates the final delivery to Adobe.

You can use two delivery models:

* **The Wallet Crew renders HTML**, and Adobe sends it.
* **Adobe renders the template**, and The Wallet Crew only sends variables.

The architecture stays the same in all cases.

* A retail Brand uses AJO for orchestration, consent, and reporting. The Wallet Crew provides the final HTML.
* A Brand already has Adobe Campaign Transactional Messaging in production. They keep governance and reporting there.
* A team uses Marketo Engage for marketing automation and wants transactional sends visible in Marketo activity logs.
* A security team requires all outbound emails to go through a single audited platform. The script provider enforces that.

## Before you start

You must implement the script interface described in [EmailSender extensibility](/connectors/custom-connector/emailsender-extensibility). This page focuses on what changes when the “provider behind the script” is Adobe.

You will also need access to your Adobe product to create and publish whatever is required to send emails (campaign, event, or template). The Wallet Crew cannot create those objects for you.

{% hint style="info" %}
If you already send emails from Adobe and only want to embed “Add to Wallet” links, you don’t need this page. Use your Adobe templates and place The Wallet Crew links behind your CTAs. See [Email Delivery](/guides-enrolment/enrolment/via-email) for that approach.
{% endhint %}

## Pick your Adobe product

Each Adobe product has its own API, assets, and governance model. Pick the one your organization already runs.

* [Adobe Journey Optimizer (AJO)](/connectors/email-provider/adobe-marketing-cloud/adobe-journey-optimizer) is the usual choice when you have API-triggered journeys available.
* [Adobe Campaign Transactional Messaging](/connectors/email-provider/adobe-marketing-cloud/adobe-campaign-transactional-messaging) fits legacy Adobe Campaign stacks with transactional events.
* [Marketo Engage (Transactional Email API)](/connectors/email-provider/adobe-marketing-cloud/marketo-engage-transactional-email-api) is a good fit when you want sends and activity tracked in Marketo.

{% hint style="warning" %}
Pick one rendering strategy. Avoid duplicating templating in both The Wallet Crew and Adobe.
{% endhint %}

## Enable the script email provider in The Wallet Crew

This is the switch that makes The Wallet Crew call your `SendEmail` implementation.

{% stepper %}
{% step %}

#### Implement `runtime.scriptable.emailEngine.SendEmail`

Start from [EmailSender extensibility](/connectors/custom-connector/emailsender-extensibility) and add your Adobe delivery code inside `SendEmail`.

Make sure your script can access Adobe credentials securely. Do not hardcode secrets in the script.
{% endstep %}

{% step %}

#### Update `/server/emails.yml`

Open the advanced configuration editor, then create or edit `/server/emails.yml`.

Set the provider type to `script`. Keep `resources` pointing to your email template directory.

{% code title="/server/emails.yml" %}

```yaml
provider:
  type: script
resources:
  - /locales/emails/
```

{% endcode %}
{% endstep %}

{% step %}

#### Trigger one transactional email and verify in Adobe

Trigger a real email (pass download link, verification email, or registration email).

Verify that Adobe receives the call and that the message is accepted. Then validate delivery in mailbox headers if needed (SPF/DKIM/DMARC).
{% endstep %}
{% endstepper %}

## Template and culture strategy

The Wallet Crew can render templates locally via `buildEmail`. Adobe can also render templates on its side, depending on the product.

Pick one of these models and keep it consistent:

* **The Wallet Crew owns the HTML.** You send rendered `Subject` and `Body` to Adobe.
* **Adobe owns the HTML.** You send only variables, and Adobe picks the template.

Culture selection remains your responsibility. The platform provides a `cultures` array. Common strategies include selecting the first culture, mapping a culture to a specific Adobe asset, or falling back to a default.

## Security and privacy notes

Treat this integration as a server-to-server connection.

* Keep all Adobe credentials server-side. Never expose them to customers.
* Prefer short-lived access tokens. Rotate client secrets regularly.
* Avoid logging full rendered email bodies. Email content can contain personal data.
* Log stable identifiers instead (template name, Adobe campaign/event id, and a correlation id).

## Troubleshooting

If emails stop sending, isolate the issue in this order:

* Confirm `/server/emails.yml` is valid YAML and saved in the right tenant.
* Confirm your script registers `runtime.scriptable.emailEngine` and exports `SendEmail`.
* Confirm Adobe authentication works (token generation and scopes).
* Confirm the Adobe asset is published and callable (campaign/journey/event/template).
* Check Adobe logs for rejected requests (missing fields, schema mismatch, rate limits).

## FAQ

<details>

<summary><strong>Which option should we choose?</strong></summary>

Pick the product your organization already runs and governs for transactional emails. If you have Adobe Journey Optimizer available for API-triggered sends, it is usually the most future-proof choice.

</details>

<details>

<summary><strong>Can we switch later?</strong></summary>

Yes. Rendering is separated from delivery. If you keep your templates in The Wallet Crew, switching the downstream Adobe product mostly becomes a script change.

</details>

<details>

<summary><strong>Do we need Adobe to host templates?</strong></summary>

Not necessarily. You can send fully rendered HTML from The Wallet Crew, or delegate rendering to Adobe. Pick one strategy to avoid inconsistencies.

</details>

<details>

<summary><strong>Do we need this integration if we already send emails from Adobe?</strong></summary>

Not always. If your Brand already sends the email from Adobe and you only want to add “Add to Wallet” links, keep the email fully in Adobe. Then embed The Wallet Crew links behind your CTAs. See [Email Delivery](/guides-enrolment/enrolment/via-email) for that approach.

Use the script provider only when you want The Wallet Crew to trigger the transactional send and delegate final delivery to Adobe.

</details>

<details>

<summary><strong>Should we send rendered HTML or only variables?</strong></summary>

Send rendered HTML when you want The Wallet Crew to be the source of truth for email content and translations. Send only variables when your email team needs full control of the template and approval workflow in Adobe.

Avoid mixing both models across journeys. It creates hard-to-debug differences between emails.

</details>

<details>

<summary><strong>Can we use multiple Adobe products at the same time?</strong></summary>

Technically yes, because your script can route sends however you want. In practice, pick one product per tenant when possible. It keeps governance, reporting, and troubleshooting clear.

</details>


# Adobe Journey Optimizer

Send Wallet Crew transactional emails via Adobe Journey Optimizer (AJO) using the script email provider.

Use this option when you have **Adobe Journey Optimizer (AJO)** and you want **API-triggered sends** that fit modern journey orchestration.

Before you go further, make sure you understand how the script provider works in The Wallet Crew. Start with [Adobe Marketing Cloud](broken://spaces/WLc8AHXW4tdrAXUBfrYF/pages/SpCitnWk5qBrFL8g3DER) and the prerequisite [EmailSender extensibility](broken://spaces/WLc8AHXW4tdrAXUBfrYF/pages/kVUaVHl41zxPF7TxBjzD).

### When to use this

You typically pick AJO when you want near real-time sends and your marketing team already operates journeys in AJO.

### Setup required in Adobe

Create an API-triggered journey or campaign that can accept an execution call. Then configure the email action.

At minimum, agree on what your script sends to AJO.

* **Fully rendered HTML** from The Wallet Crew (`Subject`, `Body`).
* Or **context variables only**, with the template managed in AJO.

{% hint style="warning" %}
Pick one rendering strategy. Avoid duplicating templating in both The Wallet Crew and Adobe.
{% endhint %}

### Implementation notes (OAuth + trigger)

AJO uses Adobe IMS for OAuth2 (client credentials). Your script typically requests an access token, then calls the AJO execution endpoint for your campaign or journey.

{% hint style="info" %}
Adobe endpoints and payload shapes depend on your org setup, region, and the AJO feature you use (journey vs campaign). Treat the snippet below as a skeleton, and align it with Adobe’s official docs for your product version.
{% endhint %}

Store these values as secrets before you test:

* `adobe-clientId`
* `adobe-clientSecret`
* `adobe-orgId`
* `adobe-sandboxName`
* `adobe-ajo-triggerUrl` (full AJO trigger URL)
* `adobe-scope` (optional, depends on your Adobe setup)

{% code title="Adobe Journey Optimizer example (SendEmail implementation)" %}

```javascript
import { getSecret } from "neo/secrets";

const CUSTOM_DOMAIN = "wallet.brand.com";
const TENANTID = "brand";

// Adobe IMS (OAuth2 client credentials)
// Your runtime provides a custom `fetch` that can perform OAuth client credentials flows.
const IMS_TOKEN_URL = "https://ims-na1.adobelogin.com/ims/token/v3";

/**
 * @typedef {Object} EmailData
 * @property {string} Subject - Rendered subject line.
 * @property {string} Body - Rendered body content.
 */

/**
 * Send an email using the provided template name and data.
 * The caller supplies the supported cultures and a callback
 * to build the rendered email content.
 *
 * @param {string} recipient - Target email address.
 * @param {string} emailTemplate - Template name to render.
 * @param {Object.<string, any>} data - Template data passed to the script.
 * @param {string[]} cultures - Available culture names from the culture provider.
 * @param {(templateName: string) => Promise<EmailData>} buildEmail
 * Callback that returns the final rendered email content.
 *
 * @returns {Promise<void>}
 */
async function sendEmail(recipient, emailTemplate, data, cultures, buildEmail) {
  const email = recipient;
  const countryCode = data["country"] || "fr";
  const language = `${cultures[0]?.toLowerCase()?.substring(0, 2) || "fr"}_${countryCode.toLowerCase()}`;
  const customerId = data["id.customerId"];

  if (!customerId) {
    throw new Error('Missing "id.customerId" in email data.');
  }

  // URL the customer should click to download their pass.
  // You can change the path to match your distribution layout.
  const url = `https://${CUSTOM_DOMAIN}/${TENANTID}/pass?id.customerId=${encodeURIComponent(customerId)}`;

  // Optional: keep The Wallet Crew rendering available.
  // If your AJO template is fully managed in Adobe, you can remove this.
  const rendered = await buildEmail(emailTemplate);

  // AJO config must be provided as secrets.
  // Use a full URL to avoid hardcoding product-specific paths in this script.
  // Example (varies by setup): "https://platform.adobe.io/journey/execute/<CAMPAIGN_OR_JOURNEY_ID>"
  const ajoTriggerUrl = await getSecret("adobe-ajo-triggerUrl");
  const orgId = await getSecret("adobe-orgId");
  const sandboxName = await getSecret("adobe-sandboxName");
  const clientId = await getSecret("adobe-clientId");
  const clientSecret = await getSecret("adobe-clientSecret");

  // Keep scope configurable. Different Adobe setups require different scopes.
  // Example values seen in the wild: "openid,AdobeID"
  let scope = "openid,AdobeID";
  try {
    scope = (await getSecret("adobe-scope")) || scope;
  } catch (e) {
    // Optional secret. Keep the default scope.
  }

  // Your runtime `fetch` handles OAuth client credentials and attaches the token.
  // This avoids manually calling IMS then forwarding the Bearer token.
  const result = await fetch(ajoTriggerUrl, {
    Method: "POST",
    Authentication: {
      mode: "OAuth2.0",
      grantType: "clientCredentials",
      sendCredentialsAsFormParams: true,
      accessTokenUrl: IMS_TOKEN_URL,
      clientId,
      clientSecret,
      scope,
    },
    Headers: {
      "x-api-key": clientId,
      "x-gw-ims-org-id": orgId,
      "x-sandbox-name": sandboxName,
      "Content-Type": "application/json",
    },
    Body: JSON.stringify({
      // The exact payload shape must match your AJO API-triggered campaign/journey configuration.
      // Keep this contract stable between your script and your AJO asset.
      recipient: {
        email,
        language,
      },
      context: {
        // Minimal variable for an Adobe-managed template:
        url,

        // Optional variables if you want to reuse The Wallet Crew rendering inside Adobe:
        subject: rendered.Subject,
        body: rendered.Body,

        // Useful metadata for routing / debugging:
        template: emailTemplate,
        customerId,
      },
    }),
    ThrowOnError: false,
  });

  if (result.StatusCode < 200 || result.StatusCode >= 300) {
    throw new Error(`AJO trigger call failed (${result.StatusCode}): ${result.ResponseText}`);
  }
}

export default function (context) {
  context.register("runtime.scriptable.emailEngine", {
    SendEmail: sendEmail,
  });
}
```

{% endcode %}

### What to validate

Trigger a real transactional email, then validate these points:

* AJO receives the execution call and accepts it.
* The AJO email action has access to the context fields you send.
* If you pass HTML, the final email renders correctly in common clients.

### FAQ

<details>

<summary><strong>Do we need an “API-triggered journey” in AJO?</strong></summary>

Yes. Your script needs a published AJO asset that can be triggered by an API call. The exact asset type (journey vs campaign) depends on what your Adobe organization uses.

</details>

<details>

<summary><strong>Can AJO send an email built by The Wallet Crew?</strong></summary>

Yes. A common pattern is to call `buildEmail()` in your script, then pass `subject` and `body` as context to AJO. Your AJO email action must be configured to use these fields.

</details>

<details>

<summary><strong>How do we test without emailing real customers?</strong></summary>

Use an AJO sandbox if you have one. If you don’t, restrict tests to internal addresses and create a dedicated “test” journey/campaign. Keep the payload contract identical to production to avoid last-minute schema breaks.

</details>

<details>

<summary><strong>Why do we need so many Adobe headers?</strong></summary>

AJO gateways commonly require org, sandbox, and API key headers for routing and authorization. The exact set can vary by Adobe setup and region, so treat Adobe’s official docs as the source of truth for your tenant.

</details>


# Adobe Campaign Transactional Messaging

Send Wallet Crew transactional emails via Adobe Campaign Transactional Messaging using the script email provider.

Use this option when your organization runs **Adobe Campaign** and already uses **Transactional Messaging** for production sends.

Before you go further, make sure you understand how the script provider works in The Wallet Crew. Start with [Adobe Marketing Cloud](broken://spaces/WLc8AHXW4tdrAXUBfrYF/pages/SpCitnWk5qBrFL8g3DER) and the prerequisite [EmailSender extensibility](broken://spaces/WLc8AHXW4tdrAXUBfrYF/pages/kVUaVHl41zxPF7TxBjzD).

### When to use this

This is a good fit when you already have Adobe Campaign governance, reporting, and pre-existing transactional events.

### Setup required in Adobe

Create and publish a **Transactional Message Event**.

Then decide whether Adobe Campaign will use the rendered HTML from The Wallet Crew or build the final email using Adobe Campaign templates and variables.

You also need a secure server-side authentication method supported by your Adobe Campaign deployment. This is often based on Adobe I/O or IMS.

### Implementation notes (event call)

Your script usually renders the email (if The Wallet Crew controls HTML), then calls the transactional event endpoint with the recipient and context.

Store these values as secrets before you test:

* `adobe-clientId`
* `adobe-clientSecret`
* `adobe-campaign-transactionalUrl` (full Transactional Message Event URL)
* `adobe-orgId` (optional, depends on your Campaign setup)
* `adobe-scope` (optional, depends on your Adobe setup)

{% code title="Adobe Campaign example (SendEmail implementation)" %}

```javascript
import { getSecret } from "neo/secrets";

const CUSTOM_DOMAIN = "wallet.brand.com";
const TENANTID = "brand";

// Adobe IMS (OAuth2 client credentials)
const IMS_TOKEN_URL = "https://ims-na1.adobelogin.com/ims/token/v3";

async function getOptionalSecret(name, fallback) {
  try {
    return (await getSecret(name)) || fallback;
  } catch (e) {
    return fallback;
  }
}

/**
 * @typedef {Object} EmailData
 * @property {string} Subject
 * @property {string} Body
 */

async function sendEmail(recipient, emailTemplate, data, cultures, buildEmail) {
  const email = recipient;
  const countryCode = data["country"] || "fr";
  const language = `${cultures[0]?.toLowerCase()?.substring(0, 2) || "fr"}_${countryCode.toLowerCase()}`;
  const customerId = data["id.customerId"];

  if (!customerId) {
    throw new Error('Missing "id.customerId" in email data.');
  }

  const url = `https://${CUSTOM_DOMAIN}/${TENANTID}/pass?id.customerId=${encodeURIComponent(customerId)}`;

  // Keep Wallet Crew rendering available.
  // If Adobe Campaign owns the template, you can remove this and only send variables.
  const rendered = await buildEmail(emailTemplate);

  const transactionalUrl = await getSecret("adobe-campaign-transactionalUrl");

  const clientId = await getSecret("adobe-clientId");
  const clientSecret = await getSecret("adobe-clientSecret");
  const scope = await getOptionalSecret("adobe-scope", "openid,AdobeID");

  // Optional. Some setups require org id headers, others do not.
  const orgId = await getOptionalSecret("adobe-orgId", null);

  const headers = {
    "x-api-key": clientId,
    "Content-Type": "application/json",
  };
  if (orgId) headers["x-gw-ims-org-id"] = orgId;

  const result = await fetch(transactionalUrl, {
    Method: "POST",
    Authentication: {
      mode: "OAuth2.0",
      grantType: "clientCredentials",
      sendCredentialsAsFormParams: true,
      accessTokenUrl: IMS_TOKEN_URL,
      clientId,
      clientSecret,
      scope,
    },
    Headers: headers,
    Body: JSON.stringify({
      // Payload must match your Transactional Message Event definition.
      email,
      ctx: {
        url,
        language,

        // Optional if you want Campaign to use Wallet Crew rendering:
        subject: rendered.Subject,
        body: rendered.Body,

        // Useful metadata:
        template: emailTemplate,
        customerId,
      },
    }),
    ThrowOnError: false,
  });

  if (result.StatusCode < 200 || result.StatusCode >= 300) {
    throw new Error(`Adobe Campaign call failed (${result.StatusCode}): ${result.ResponseText}`);
  }
}

export default function (context) {
  context.register("runtime.scriptable.emailEngine", {
    SendEmail: sendEmail,
  });
}
```

{% endcode %}

### What to validate

Trigger a real transactional email, then validate these points:

* Your Transactional Message Event is published and callable.
* The payload schema matches the event definition.
* Adobe Campaign accepts the request and processes the message.

### FAQ

<details>

<summary><strong>Do we need a Transactional Message Event?</strong></summary>

Yes. Your script must call a published Transactional Messaging Event endpoint. That event defines the expected payload schema and what variables are available in your Adobe Campaign template.

</details>

<details>

<summary><strong>Can Adobe Campaign render the email instead of The Wallet Crew?</strong></summary>

Yes. In that setup, your script sends only the variables (for example, the pass download URL and customer metadata). Adobe Campaign owns the HTML, subject, and translations.

</details>

<details>

<summary><strong>What authentication method should we use?</strong></summary>

It depends on your Adobe Campaign deployment and how your Adobe organization manages server-to-server access. This page shows an IMS-based approach because it is common, but you should align the final auth method with your Adobe admin team and Adobe’s official documentation for your environment.

</details>

<details>

<summary><strong>What’s the most common reason for request rejection?</strong></summary>

Schema mismatch. The event definition is strict. If your payload fields don’t match the event’s expected structure, Campaign will reject or ignore fields, and templates will render empty values.

</details>


# Marketo Engage (Transactional Email API)

Send Wallet Crew transactional emails via Marketo Engage using the script email provider.

Use this option when your organization uses **Marketo Engage** and wants transactional sends tracked in Marketo activity logs.

Before you go further, make sure you understand how the script provider works in The Wallet Crew. Start with [Adobe Marketing Cloud](broken://spaces/WLc8AHXW4tdrAXUBfrYF/pages/SpCitnWk5qBrFL8g3DER) and the prerequisite [EmailSender extensibility](broken://spaces/WLc8AHXW4tdrAXUBfrYF/pages/kVUaVHl41zxPF7TxBjzD).

### When to use this

This is often the simplest REST model, but it assumes you manage and approve the email template in Marketo.

### Setup required in Marketo

Create the email asset you want to send and get it approved. Approval rules vary by Marketo setup.

Then decide how you map The Wallet Crew output:

* Use Marketo tokens or variables to inject `Subject` and `Body`.
* Or keep the subject and body in Marketo and only pass contextual data.

### Implementation notes (token + send)

Marketo instances are region-specific. Your script usually requests a Marketo access token, then calls the transactional send endpoint for the chosen email asset.

Store these values as secrets before you test:

* `marketo-baseUrl` (example: `https://123-ABC-456.mktorest.com`)
* `marketo-clientId`
* `marketo-clientSecret`
* `marketo-emailId` (the Marketo email asset identifier you send)

{% hint style="info" %}
Marketo OAuth token endpoints can differ slightly by instance and configuration. If your Marketo token endpoint requires query parameters or a specific HTTP method, adapt the authentication settings accordingly.
{% endhint %}

{% code title="Marketo Engage example (SendEmail implementation)" %}

```javascript
import { getSecret } from "neo/secrets";

const CUSTOM_DOMAIN = "wallet.brand.com";
const TENANTID = "brand";

async function sendEmail(recipient, emailTemplate, data, cultures, buildEmail) {
  const email = recipient;
  const countryCode = data["country"] || "fr";
  const language = `${cultures[0]?.toLowerCase()?.substring(0, 2) || "fr"}_${countryCode.toLowerCase()}`;
  const customerId = data["id.customerId"];

  if (!customerId) {
    throw new Error('Missing "id.customerId" in email data.');
  }

  const url = `https://${CUSTOM_DOMAIN}/${TENANTID}/pass?id.customerId=${encodeURIComponent(customerId)}`;
  const rendered = await buildEmail(emailTemplate);

  const baseUrl = await getSecret("marketo-baseUrl");
  const clientId = await getSecret("marketo-clientId");
  const clientSecret = await getSecret("marketo-clientSecret");
  const marketoEmailId = await getSecret("marketo-emailId");

  const sendUrl = `${baseUrl}/rest/v1/email/${encodeURIComponent(marketoEmailId)}/send.json`;

  // Your runtime `fetch` handles OAuth client credentials and attaches the token.
  const result = await fetch(sendUrl, {
    Method: "POST",
    Authentication: {
      mode: "OAuth2.0",
      grantType: "clientCredentials",
      sendCredentialsAsFormParams: true,
      accessTokenUrl: `${baseUrl}/identity/oauth/token`,
      clientId,
      clientSecret,
    },
    Headers: {
      "Content-Type": "application/json",
    },
    Body: JSON.stringify({
      input: [
        {
          email,
          variables: [
            { name: "url", value: url },
            { name: "language", value: language },
            { name: "subject", value: rendered.Subject },
            { name: "body", value: rendered.Body },
            { name: "customerId", value: customerId },
            { name: "template", value: emailTemplate },
          ],
        },
      ],
    }),
    ThrowOnError: false,
  });

  if (result.StatusCode < 200 || result.StatusCode >= 300) {
    throw new Error(`Marketo send call failed (${result.StatusCode}): ${result.ResponseText}`);
  }
}

export default function (context) {
  context.register("runtime.scriptable.emailEngine", {
    SendEmail: sendEmail,
  });
}
```

{% endcode %}

{% hint style="info" %}
Marketo requires the email asset to exist (and often to be approved) before it can be used for sends.
{% endhint %}

### What to validate

Trigger a real transactional email, then validate these points:

* The email asset exists and is approved.
* Marketo accepts the send call.
* Variables map to what your Marketo template expects.

### FAQ

<details>

<summary><strong>Do we need to create the email template in Marketo?</strong></summary>

Yes. Marketo requires an existing email asset for transactional sends, and many setups require the asset to be approved. Your script can still pass variables, but Marketo needs the container asset.

</details>

<details>

<summary><strong>Can The Wallet Crew still render the HTML?</strong></summary>

Yes. You can call `buildEmail()` and pass `subject` and `body` as variables. Your Marketo email must be built to inject those variables into the right places.

</details>

<details>

<summary><strong>What’s the quickest way to troubleshoot?</strong></summary>

First check that the asset is approved, then check the Marketo API response body for a specific error code. If the API call succeeds but the email renders badly, validate that your Marketo template expects the same variable names you send.

</details>

<details>

<summary><strong>Can we use different Marketo instances per environment?</strong></summary>

Yes. Configure different secrets and endpoints per tenant (staging vs production). Keep variable naming consistent across environments to avoid template drift.

</details>


# Mailchimp

Configure The Wallet Crew to send transactional emails via Mailchimp Transactional (Mandrill).

The Wallet Crew can send transactional emails through Mailchimp Transactional (Mandrill). This covers messages like pass download links, verification emails, etc.

By default, The Wallet Crew uses **its own SendGrid account**. You can switch to **your own Mailchimp Transactional account** when you want to centralize email activity in Mandrill, or when you already rely on Mandrill for deliverability monitoring.

This setup is limited to transactional sending. It does not integrate Mailchimp Marketing features like audiences or campaigns.

If you’re not sure which option to pick, start with [Email provider](/connectors/email-provider).

## Configure your own Mailchimp Transactional (Mandrill) account

Before you update The Wallet Crew configuration, make sure Mandrill can authenticate your sender identity. In practice, that means having a Mailchimp Transactional account, generating a Transactional API key, and validating the sender domain or email address you want to use.

{% stepper %}
{% step %}
**Decide what sender domain you want to use**

Prefer a dedicated subdomain such as `wallet.yourbrand.com` or `registration.yourbrand.com`. This keeps email authentication isolated from other mail systems.

{% hint style="info" %}
Using a dedicated subdomain reduces exposure and improves security through better isolation. We recommend using the same custom domain as your app when it makes sense for your setup.
{% endhint %}
{% endstep %}

{% step %}
**Create a Transactional API key**

Create an API key in Mailchimp Transactional (Mandrill), because The Wallet Crew uses it to call Mandrill’s send APIs on your behalf.

<div data-with-frame="true"><figure><img src="/files/leamQkcQWgPhO3WhtmyK" alt="API configuration in Mailchimp Transactional." width="375"><figcaption><p>API configuration in Mailchimp Transactional.</p></figcaption></figure></div>

Follow this guide: [Generate your API key](https://mailchimp.com/developer/transactional/guides/quick-start/#generate-your-api-key).
{% endstep %}

{% step %}
**Update `/server/emails.yml`**

Open the advanced configuration editor:

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/settings/configuration" class="button secondary" data-icon="chevrons-right">Administration console - Advanced Configuration</a></p>

Then create or edit `/server/emails.yml`:

{% code title="/server/emails.yml" %}

```yaml
provider:
  type: mailchimp
  apiKey: md-xxxx
  from:
    email: support@yourbrand.com
    name: Your brand support
resources:
  - /locales/emails/
```

{% endcode %}

Replace `md-xxxx` with your Mandrill API key. Then set the `from` values to a sender identity that Mandrill accepts.

{% hint style="warning" %}
Treat your Mandrill API key like a password.

Do not paste it in tickets or screenshots.
{% endhint %}
{% endstep %}

{% step %}
**Save and test**

Save the file in the admin console to apply the provider change. Trigger a single transactional email from your usual flow, then confirm delivery in Mailchimp Transactional activity logs.
{% endstep %}
{% endstepper %}

## Troubleshooting

Most issues come from using the wrong key type or sending from an unverified identity. If email sending fails or nothing seems to change, start with these checks:

* **Mailchimp Marketing vs Transactional**: you must use a **Transactional (Mandrill)** key.
* **401/403 from Mailchimp**: check the key, and that Transactional is enabled.
* **Emails not delivered**: verify your sender domain/email in Mailchimp Transactional.
* **Nothing changes after editing**: confirm you edited `/server/emails.yml` in the right tenant and saved it.

## FAQ

<details>

<summary><strong>Is this the same as “Mailchimp marketing emails”?</strong></summary>

**No**. This integration only uses **Mailchimp Transactional (Mandrill)** to send transactional messages.

</details>

<details>

<summary><strong>Do I need a paid Mailchimp add-on?</strong></summary>

Usually yes, because Transactional (Mandrill) is a separate product from standard Mailchimp Marketing plans.

</details>

<details>

<summary><strong>Where do I configure Mailchimp in The Wallet Crew?</strong></summary>

Edit `/server/emails.yml` in the advanced configuration editor.

</details>

<details>

<summary><strong>Do we need to authenticate our domain in Mailchimp Transactional?</strong></summary>

**Yes**. Verify the sender identity you use for `from.email` in Mailchimp Transactional. If you send from a domain, set up authentication (SPF/DKIM) and add a DMARC record for that domain or subdomain.

</details>

<details>

<summary><strong>Can I keep SendGrid in staging and Mailchimp in production?</strong></summary>

Yes, but it’s not recommended.

Each tenant has its own configuration, so you can choose different providers per environment. In practice, using different providers makes troubleshooting harder. It also increases the risk of provider-specific differences between staging and production (sender authentication, deliverability behavior, activity logs, and rate limits).

If you need a safe test environment, prefer using the **same provider** in both environments. Use a different sender subdomain (for example `staging.wallet.yourbrand.com`) and send only to internal addresses.

</details>

<details>

<summary><strong>What’s the fastest way to validate my config?</strong></summary>

Save `/server/emails.yml`, trigger a single email, then verify the event in Mailchimp Transactional activity logs.

</details>


# Salesforce Marketing Cloud

Configure The Wallet Crew to send transactional emails through Salesforce Marketing Cloud.

Use this connector when you want The Wallet Crew to send **transactional emails** through **Salesforce Marketing Cloud**, while Salesforce Marketing Cloud remains the place where your Brand manages email assets, tracking, and reporting.

This integration uses the **script email provider**. The Wallet Crew triggers the send. Your script forwards the event to Salesforce Marketing Cloud.

## How it works

The Wallet Crew calls your implementation of `runtime.scriptable.emailEngine.SendEmail`. Your script then calls the Salesforce Marketing Cloud REST API to fire an event (using an `EventDefinitionKey`). Salesforce Marketing Cloud uses that event payload to render and send the email.

This model avoids duplicating templates. Salesforce Marketing Cloud owns the template. The Wallet Crew only sends the variables Salesforce Marketing Cloud needs, like the pass download URL and localized CTA label.

If you haven’t set up the script provider yet, start with [EmailSender extensibility](/connectors/custom-connector/emailsender-extensibility).

## Before you start

You need three things:

* A Salesforce Marketing Cloud **Installed Package** that can call REST APIs (client id + client secret).
* A Salesforce Marketing Cloud asset that can be **triggered by API**, exposing an `EventDefinitionKey`.
* A stable identifier in your Wallet Crew email payload (example: `id.customerId`) to generate the pass URL.

## Setup required in Salesforce Marketing Cloud

In Salesforce Marketing Cloud, create an API-triggered entry point and the associated email content.

1. Create an **Installed Package** and keep the **Client Id** and **Client Secret**.
2. Create the send asset you want to trigger (typically a journey entry event or an API event), then copy its `EventDefinitionKey`.
3. Make sure your Salesforce Marketing Cloud email template expects the same variable names you will send in `Data`.

{% hint style="info" %}
Salesforce Marketing Cloud setup varies by account configuration and feature set. Keep your payload contract stable: the field names in `Data` should match what your Salesforce Marketing Cloud asset expects.
{% endhint %}

## Enable Salesforce Marketing Cloud in The Wallet Crew

Set the provider to `script` so The Wallet Crew calls your `SendEmail` implementation.

{% code title="/server/emails.yml" %}

```yaml
provider:
  type: script
resources:
  - /locales/emails/
```

{% endcode %}

### Script example (trigger a Salesforce Marketing Cloud event)

This example triggers a Salesforce Marketing Cloud event using the REST endpoint `interaction/v1/events`. It sends a localized title, a localized CTA label, and a Wallet Crew pass URL built from a customer identifier.

{% hint style="warning" %}
This implementation delegates rendering to Salesforce Marketing Cloud. The Wallet Crew `buildEmail()` callback is intentionally not used.
{% endhint %}

{% code title="Salesforce Marketing Cloud example (SendEmail implementation)" %}

```javascript
const CUSTOM_DOMAIN = "wallet.brand.com";
const TENANTID = "brand";
const SMFC_DOMAIN = "xxx";

/**
 * @typedef {Object} EmailData
 * @property {string} Subject - Rendered subject line.
 * @property {string} Body - Rendered body content.
 */

/**
 * Send an email using the provided template name and data.
 * The caller supplies the supported cultures and a callback
 * to build the rendered email content.
 *
 * @param {string} recipient - Target email address.
 * @param {string} emailTemplate - Template name to render.
 * @param {Object.<string, any>} data - Template data passed to the script.
 * @param {string[]} cultures - Available culture names from the culture provider.
 * @param {(templateName: string) => Promise<EmailData>} buildEmail
 * Callback that returns the final rendered email content.
 *
 * @returns {Promise<void>}
 */
async function sendEmail(recipient, emailTemplate, data, cultures, buildEmail){

  const customerId = data["id.customerId"];
  const url = `https://${CUSTOM_DOMAIN}/${TENANTID}/pass?id.customerId=${customerId}`;  

  const locales = {
    "en": {
      title: "🎉 Your Account is Ready – Add Your Pass to Wallet!",
      label: "Add to Wallet"
    },
    "fr": {
      title: "🎉 Votre compte est prêt – Ajoutez votre pass au Wallet !",
      label: "Ajouter au Wallet"
    }
  };

  const locale = locales[cultures[0]];

  const response = await fetch(`https://${SMFC_DOMAIN}.rest.marketingcloudapis.com/interaction/v1/events`,  {
    Method : "POST", 
    Authentication : {
        mode : 'OAuth2.0', 
        grantType : 'clientCredentials',
        accessTokenUrl : `https://${SMFC_DOMAIN}.auth.marketingcloudapis.com/v2/token`, 
        sendCredentialsAsFormParams: true,
        clientId: await getSecret('SFMC-CLIENTID'), 
        clientSecret : await getSecret('SFMC-CLIENTSECRET')
    }, 
    Headers: {
      "Content-Type": "application/json",
    },
    Body: {
      "ContactKey": recipient,
      "EventDefinitionKey": "confirmationCompteNeostore",
      "Data": {
          "SubscriberKey": recipient,
          "EmailAddress": recipient,
          "Title": locale.title,
          "Url": url,
          "LabelCTA": locale.label,
      }
    }
  });
  const responseData = JSON.parse(response.ResponseText); 
  if(!responseData?.eventInstanceId){
    throw new Error(`error while sending custom email status : ${response.StatusCode} - content : ${response.ResponseText}`)
  }
}

export default function(context) {
  context.register('runtime.scriptable.emailEngine', {
    SendEmail: sendEmail 
  })
}
```

{% endcode %}

### What to validate

Trigger a real transactional email, then validate end-to-end:

* The Wallet Crew calls your script without errors.
* The Salesforce Marketing Cloud API call returns an `eventInstanceId`.
* Salesforce Marketing Cloud renders the email with `Title`, `Url`, and `LabelCTA`.
* The CTA opens the Wallet Crew URL and the pass can be installed.

## Troubleshooting

If sends fail, isolate the problem in this order:

* **OAuth fails (401/403)**: client id/secret is wrong, revoked, or the installed package lacks API access.
* **No `eventInstanceId`**: the `EventDefinitionKey` is invalid, unpublished, or the payload schema is rejected.
* **Empty variables in the email**: the Salesforce Marketing Cloud template expects different field names than what you send in `Data`.
* **Wrong language**: `cultures[0]` does not match your locale map. Add a fallback (example: default to `en`).

## FAQ

<details>

<summary><strong>Does Salesforce Marketing Cloud or The Wallet Crew own the email HTML?</strong></summary>

Salesforce Marketing Cloud owns the HTML in this model. The Wallet Crew sends only variables (title, CTA label, URL) so your marketing team can iterate on the template without shipping Wallet Crew changes.

</details>

<details>

<summary><strong>Can we still use Wallet Crew templates and <code>buildEmail()</code>?</strong></summary>

Yes, but it becomes a different strategy. In that model, The Wallet Crew renders `Subject` and `Body`, and Salesforce Marketing Cloud is only used as a delivery gateway. If you want that, align the Salesforce Marketing Cloud asset to accept rendered HTML and avoid double-templating.

</details>

<details>

<summary><strong>Where do we store the SFMC credentials?</strong></summary>

Store them as tenant secrets and load them at runtime (as in the example with `getSecret('SFMC-CLIENTID')` and `getSecret('SFMC-CLIENTSECRET')`). Do not hardcode credentials in scripts.

</details>

<details>

<summary><strong>What should we use as <code>ContactKey</code>?</strong></summary>

Use a stable Salesforce Marketing Cloud contact identifier. Many Brands use the email address, but you can also use a CRM id if that is your Salesforce Marketing Cloud contact key strategy. Keep it consistent with how your Journey/asset resolves recipients.

</details>


# SendGrid

Configure how The Wallet Crew sends transactional emails with SendGrid.

The Wallet Crew can send transactional emails through SendGrid. This covers messages like pass download links, verification emails, etc.

By default, The Wallet Crew uses **its own SendGrid account**. You can switch to **your own SendGrid account** when you need full ownership of deliverability, reputation, and billing.

If you’re not sure which option to pick, start with [Email provider](/connectors/email-provider).

### Option 1 : Use The Wallet Crew SendGrid account

This is the simplest option, and it’s the default. You don’t need to create a SendGrid account or manage API keys. The Wallet Crew takes care of it.

If you want customers to see your Brand in their inbox, enable a **custom sending domain**. This improves deliverability. It also reduces spoofing and phishing risks.

{% hint style="info" %}
When you use The Wallet Crew SendGrid account, The Wallet Crew must enable the custom sending domain on its side. You will still need to add DNS records (SPF/DKIM, and ideally DMARC) on your domain.
{% endhint %}

{% stepper %}
{% step %}

#### Decide what sender domain you want to use

Prefer a dedicated subdomain such as `wallet.yourbrand.com` or `registration.yourbrand.com`. This keeps email authentication isolated from other mail systems.

{% hint style="info" %}
Delegating a dedicated subdomain reduces your attack surface and improves security by isolating pass-related traffic. We recommend using the same custom domain as your app.
{% endhint %}
{% endstep %}

{% step %}

#### Ask support to enable your sending domain

Contact The Wallet Crew support with the subdomain you want to use. The team will provide the DNS records to add and will enable the domain in SendGrid.
{% endstep %}

{% step %}

#### Configure DNS (SPF, DKIM, DMARC)

Add the DNS records provided by The Wallet Crew, then wait for DNS propagation.

For the general process and why it matters, see [Custom Domain](/configure/advanced-configuration/platform/custom-domain).
{% endstep %}

{% step %}

#### Test a real send

Trigger one transactional email and confirm:

* the email is delivered (not blocked or quarantined)
* the visible sender matches your intended domain
* SPF/DKIM pass (check in your mailbox headers if needed)
  {% endstep %}
  {% endstepper %}

### Option 2: Use your own SendGrid account

{% stepper %}
{% step %}

#### Create a SendGrid API key

In SendGrid, go to `Settings` → `API Keys`. Create an API key with **Mail Send** permissions.
{% endstep %}

{% step %}

#### Update `/server/emails.yml`

Open the advanced configuration editor:

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/settings/configuration" class="button secondary">The Wallet Crew Administration - Advanced configuration</a></p>

Then create or edit `/server/emails.yml`.

{% code title="/server/emails.yml" %}

```yaml
provider:
  type: sendgrid
  apiKey: YOUR_SENDGRID_API_KEY
  from:
    email: no-reply@yourbrand.com
    name: Your Brand
resources:
  - /locales/emails/
```

{% endcode %}

Use a `from.email` that belongs to a domain you authenticate in SendGrid.

{% hint style="warning" %}
Treat your SendGrid API key like a password.

Do not paste it in tickets or screenshots.
{% endhint %}
{% endstep %}

{% step %}

#### Configure sender authentication in SendGrid

Authenticate your sending domain in SendGrid using the standard “Domain Authentication” flow. This configures SPF and DKIM. Add a DMARC record for your sending domain if needed. This improves deliverability and reduces spoofing risk.
{% endstep %}

{% step %}

#### Save and test

Save the file. Trigger a single transactional email. Verify the event in your SendGrid activity logs.
{% endstep %}
{% endstepper %}

## Troubleshooting

* If SendGrid returns **401** or **403**, your API key is invalid or missing permissions.
* If the “from” address is rejected, your domain is not authenticated. Check SPF and DKIM first.
* If emails land in spam, re-check authentication, DMARC policy, and sender reputation.
* If nothing changes after editing, confirm you saved the right tenant file. The file must be `/server/emails.yml`.

## FAQ

<details>

<summary><strong>Where do I configure SendGrid in The Wallet Crew?</strong></summary>

Edit `/server/emails.yml` in the advanced configuration editor.

</details>

<details>

<summary><strong>Can we keep The Wallet Crew SendGrid account instead of using our own?</strong></summary>

**Yes**. The Wallet Crew uses its own SendGrid configuration by default.

If you keep it, you can still send from a domain you control. Ask support to enable a custom sending domain, then configure SPF/DKIM and DMARC on your DNS.

</details>

<details>

<summary><strong>Do we need to authenticate our domain in SendGrid?</strong></summary>

**Yes**. Enable SendGrid Domain Authentication (SPF/DKIM). Also add a DMARC record for the domain or subdomain you use for `from.email`.

</details>

<details>

<summary><strong>Can we use different SendGrid accounts per environment?</strong></summary>

Yes. Each tenant has its own configuration. You can use different API keys per tenant.

</details>

<details>

<summary><strong>What’s the fastest way to validate the integration?</strong></summary>

Save `/server/emails.yml`, trigger a single transactional email, then verify it in your SendGrid Activity feed.

</details>


# Point of Sale (POS)

Connect POS systems to The Wallet Crew so wallet passes can be identified, validated, and updated from checkout and redemption flows.

POS systems are the operational source for checkout and redemption events. The Wallet Crew connects those systems to Apple Wallet and Google Wallet so passes stay usable at the moment of transaction.

This matters because wallet is not just a distribution channel. At point of sale, the pass must be readable, recognized, and aligned with the latest business rules.

## How POS integrations work

In a POS integration:

1. The POS remains the source of truth for transaction and redemption data.
2. The Wallet Crew maps identifiers and pass data to wallet-compatible payloads.
3. Wallet updates reflect status changes that matter at checkout or after redemption.

This keeps operational logic in existing systems while making wallet passes reliable in-store.

<details>

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

* A retailer scans a loyalty pass at checkout, then refreshes the points balance.
* A gift-card redemption changes the pass balance immediately after payment.
* A service counter validates a membership pass before applying its benefits.

</details>

### What POS integrations usually cover

Typical POS integrations include:

* pass identification at checkout or service counter
* redemption events and post-redemption status updates
* optional synchronization of balances, eligibility, or usage counters

### Available POS connectors

The available connector guides cover the following POS platforms:

* [Adyen](/connectors/pos/adyen)
* [Cegid](/connectors/pos/cegid)
* [Newstore](/connectors/pos/newstore)
* [Openbravo](/connectors/pos/openbravo)
* [Shopify POS](/connectors/pos/shopify-pos)
* [Square](/connectors/pos/square)
* [TCPOS](/connectors/pos/tcpos)

Each guide documents the platform-specific setup and supported behavior.

### POS systems not listed

An unlisted POS can become a standard connector. The Wallet Crew and the POS partner jointly scope that option when the integration can support multiple Brands.

For a tenant-specific POS, use a [custom connector](/connectors/custom-connector). Tenant scripting can call private APIs and apply proprietary mapping rules. Define the identifier, API contract, trigger model, and operational owner before implementation.

### Responsibilities

| Responsibility area              | POS or partner system                                  | The Wallet Crew                                    |
| -------------------------------- | ------------------------------------------------------ | -------------------------------------------------- |
| Transaction and redemption truth | Owns operational records and business validation rules | Does not replace POS business logic                |
| Identifier governance            | Defines stable identifiers used at scan or lookup time | Uses identifiers to resolve and update passes      |
| Wallet payload lifecycle         | Provides event/data inputs                             | Generates and updates Apple/Google wallet payloads |
| Optional custom logic            | Implements proprietary POS-specific flows              | Provides runtime hooks and wallet orchestration    |

### FAQ

<details>

<summary><strong>Does the POS remain the source of truth?</strong></summary>

Yes. The Wallet Crew extends POS data to wallet experiences, but transaction logic and redemption authority remain in the POS stack.

</details>

<details>

<summary><strong>Can we integrate if our POS is not documented here?</strong></summary>

Yes. The Wallet Crew and the POS partner can scope a standard connector. For project-specific flows, use a [custom connector](/connectors/custom-connector).

</details>

<details>

<summary><strong>What must be validated before a POS rollout?</strong></summary>

Validate the pass identifier, scan path, redemption authority, and pass update trigger. Test the flow with production scanner hardware before rollout.

</details>

<details>

<summary><strong>What should be decided first in a POS project?</strong></summary>

Start with identifier strategy, redemption flow ownership, and update triggers. These three decisions define most of the implementation shape.

</details>


# Adyen

## Displaying a QR Code on an Adyen Terminal

You can configure an Adyen terminal to display a QR code by following these steps

#### Example

<div data-with-frame="true"><figure><img src="/files/puUGn0rxm5pU8psOGrds" alt="Example" width="375"><figcaption></figcaption></figure></div>

### Prerequisites

* Ensure you have access to the [Adyen Customer Area](https://ca-live.adyen.com/ca/ca/overview/default.shtml).
* Obtain the QR code image specific to your store from The Wallet Crew administration console (details below).

### Steps to Configure the QR Code on the Adyen Terminal

1. **Log in to the Adyen Customer Area**\
   Access your Adyen account using the following link:\
   [Adyen Customer Area](https://ca-live.adyen.com/ca/ca/overview/default.shtml){target="\_blank"}.
2. **Navigate to Terminal Settings**
   * Go to the **`In-person Payments`** section.
   * Select **`Terminal Settings`** from the menu.
   * Then **`Customization`** menu
3. **Download the QR Code from The Wallet Crew**
   * To obtain the QR code specific to your store, access The Wallet Crew administration console here:\
     [Redirects - The Wallet Crew Administration Console](https://admin.thewalletcrew.io/tenant/~/tools/redirects)
   * Download the QR code image and save it in an accessible location.
4. **Upload the QR Code Image**
   * Locate the **`Logo`** section in the terminal settings.
   * Upload the image of the QR code.

{% hint style="info" %}
The size requirements for the QR code image depend on the specific terminal model. Refer to the Adyen documentation for exact dimensions.
{% endhint %}

<figure><img src="/files/eOrRBFsL1MGJy56fIfVU" alt="The size requirements for the QR code image depend on the specific terminal model. Refer to the Adye"><figcaption></figcaption></figure>

## How to Set Up Adyen Terminals with Apple Wallet Loyalty Card Notifications Using Beacon Technology

Using **Beacon Technology** ([learn more from Apple's documentation](https://developer.apple.com/ibeacon/)), you can configure Adyen terminals to send notifications to nearby iPhones with an Apple Wallet loyalty card when they are within range (e.g., 50 cm). Here's how to set it up.

#### Enhancing Loyalty Card Notifications with Adyen and Apple Wallet

Adyen terminals equipped with beacon technology allow seamless engagement with customers by delivering real-time notifications to their Apple Wallet loyalty cards. This integration is a powerful tool for businesses to enhance customer experience and boost loyalty program engagement.

**Key Benefits:**

* **Real-Time Engagement:** Notify customers about loyalty benefits or promotional offers as they approach the terminal.
* **Seamless Integration:** Works directly with Apple Wallet and Adyen terminals.
* **Customizable Notifications:** Tailor messages to match your brand's tone and context.

#### Example

<figure><img src="/files/MA8gNRiPqFjcY40Qnutx" alt="Example (2)"><figcaption></figcaption></figure>

### Steps to Configure Beacon Technology

**1. Log in to the Adyen Customer Area**

* Access your Adyen account: [Adyen Customer Area](https://ca-live.adyen.com/ca/ca/overview/default.shtml){target="\_blank"}.

**2. Enable Beacons in Adyen Terminal Settings**

* Navigate to the **`In-person Payments`** section.
* Select **`Terminal Settings`** and then go to the **`Connectivity`** tab.
* In the **`Beacon`** section:
  * **Enable Beacons** by toggling the option.
  * Specify a unique **UUID**. You can generate a new one with the reset button from neostore or use an existing one from an existing beacon configuration.
  * Set the **Major** and **Minor** values (any number between 0 and 65535).

<figure><img src="/files/DPJ2ovJ6ka0txGwFLLfP" alt="Major"><figcaption></figcaption></figure>

**3. Configure Beacon Settings in The Wallet Crew**

* Log in to the [The Wallet Crew Administration Console](https://admin.neostore.cloud/tenant/~/passTypes).
* Edit a **Template**:
  * Open the **`Apple`** tab.
  * Navigate to the **`Beacon`** section.
  * Enter the same **UUID**, **Major**, and **Minor** values configured in the Adyen administration console.
  * Specify a **Label**. This is the text that will be displayed on the iPhone notification.

<figure><img src="/files/ylNeUMUgPasRgjU63cNU" alt="Label"><figcaption></figcaption></figure>

**4. Test the Beacon Setup**

When an iPhone is within range (approximately 50 cm) of the configured Adyen terminal, a notification should appear displaying the label text.

> **Pro Tip:** If the notification does not appear as expected, ensure the beacon settings are consistent across the Adyen and The Wallet Crew configurations. Use a testing environment to refine configurations before deploying to production.

### Optimizing Notifications for Apple Wallet Loyalty Cards

* **Personalize Your Message:** Ensure that the notification text resonates with your audience. Use promotional hooks or loyalty rewards to encourage engagement.
* **Leverage Analytics:** Use Adyen’s reporting tools to monitor engagement and refine strategies based on customer interactions.
* **Stay Updated:** Regularly update your beacon settings to reflect seasonal campaigns or business changes.

### Additional Notes

* Testing range and compatibility may vary depending on the environment and iPhone model. Adjust settings if necessary.
* Refer to [Apple’s Beacon Technology Documentation](https://developer.apple.com/ibeacon/) for advanced customization and troubleshooting.

By utilizing Adyen terminals with Apple Wallet loyalty cards and beacon technology, businesses can deliver unparalleled customer experiences, driving repeat visits and increasing loyalty program participation.


# Cegid


# Livestore

This guide explains how to enable the **external customer form** extension in **Cegid Retail Live Store**.

Once enabled, LiveStore opens an enrolment form hosted by The Wallet Crew when staff create or edit a customer. After submission, staff are redirected back to the LiveStore customer details page. You can also enable a QR code mode so customers can complete enrolment on their own phone.

<details>

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

* A sales associate creates a new loyalty customer in Live Store. The Wallet Crew form collects the data and creates the customer in Cegid Y2.
* A sales associate edits an existing customer. The Wallet Crew form updates the customer in Cegid Y2, then returns to the customer detail page.
* A store uses a tablet at the entrance. A customer scans a QR code and completes enrolment in a self-service flow.

</details>

### Prerequisites

You need access to configure both Live Store and The Wallet Crew.

On the Cegid side, you need permission to edit **newpossettings** at the **global**, **country**, or **store** level.

On The Wallet Crew side, your tenant must have the **Cegid Retail Y2 connector** configured and working.

* If you have not connected Y2 yet, start with [Connect with Cegid Retail Y2](/connectors/pos/cegid/connect-with-cegid-retail-y2).
* If you need to verify which customer fields are synced, see [Cegid Retail Y2 fields mapping](/connectors/pos/cegid/cegid-retail-y2-fields-mapping).

### Setup

{% stepper %}
{% step %}

#### Create an API key in The Wallet Crew

Create an API key that Live Store will use to call The Wallet Crew endpoints.

1. Open API Key management page

<p align="center"><a href="https://admin.thewalletcrew.io/tenant/~/apiKeys" class="button secondary" data-icon="chevrons-right">API Key management</a><br></p>

2. Create a new API key with scope `tenant.y2.listener`.
3. Copy the generated value and store it in your secret manager.

You will use it as the `X-API-KEY` header in LiveStore configuration.
{% endstep %}

{% step %}

#### Configure The Wallet Crew (runtime)

This extension requires a LiveStore specific configuration in your tenant runtime.

Update your runtime configuration:

1. In Advanced Configuration, on file `security.yml`, add an account challenger of type `livestore`.
2. Update your enrolment flow to add a `livestore` flow element.
3. Create `server/livestore.yml`:

```yaml
layout: mobile_ls
useTabletMode: false
provider: y2
customerRedirectLayout: mobile_livestore
```

4. Create or update both referenced layouts (`mobile_ls` and `mobile_livestore`).
   {% endstep %}

{% step %}

#### Configure Live Store (newpossettings)

Open the newpossettings admin in your Live Store environment:

* Test: `https://<your-tenant>-test-retail-ondemand.cegid.cloud/Y2/newpossettings/`
* Prod: `https://<your-tenant>-retail-ondemand.cegid.cloud/Y2/newpossettings/`

Configure the extension at the **global**, **country**, or **store** level. It is not available at the register level.

<div data-with-frame="true"><figure><img src="/files/T5T2D1jeW6dNUuWjF0YP" alt="Cegid newpossettings scope selection showing Global, Country, and Store level configuration."><figcaption><p>Choose the scope where the extension applies (global, country, or store).</p></figcaption></figure></div>

Set the `LiveStore_Connector_ExternalCustomerForm` entry with your tenant values:

{% tabs %}
{% tab title="Production" %}

```yaml
apiEndpoint: https://app.neostore.cloud/api/<YOUR_TENANTID>/external/livestore/session
endpoint: https://app.neostore.cloud/api/<YOUR_TENANTID>/external/livestore
headerName: X-API-KEY
headerValue: <YOUR_API_KEY>
```

{% hint style="info" %}
Don't forget to replace \<YOUR\_TENANTID> and \<YOUR\_API\_KEY> with the associated value
{% endhint %}

{% hint style="info" %}
If you do have a custom domain configure, replace app.neostore.cloud with your custom domain
{% endhint %}
{% endtab %}

{% tab title="Staging" %}

```yaml
active: true
apiEndpoint: https://app-qa.neostore.cloud/api/<YOUR_TENANTID>/external/livestore/session
endpoint: https://app-qa.neostore.cloud/api/<YOUR_TENANTID>/external/livestore
headerName: X-API-KEY
headerValue: <YOUR_API_KEY>
```

{% hint style="info" %}
Don't forget to replace \<YOUR\_TENANTID> and \<YOUR\_API\_KEY> with the associated value
{% endhint %}
{% endtab %}
{% endtabs %}

If you need to pin a specific store, set the extension at the store level and add `storeId`:

```yaml
endpoint: https://app.neostore.cloud/api/<tenantId>/external/livestore?storeId=<storeId>
```

{% endstep %}

{% step %}

#### Validate the flow

Validate in a test environment first.

1. In Live Store, open the customer create or edit screen.
2. Confirm Live Store redirects to the enrolment form.
3. Submit the form with test data.
4. Confirm you are redirected back to the Live Store customer details page.

If you get an authorization error, double-check the `X-API-KEY` header value and the API key scope.
{% endstep %}
{% endstepper %}

### Optional: show a QR code for self-service enrolment

Use this when a store uses a tablet and wants customers to continue on their own phone.

Enable tablet mode in `server/livestore.yml` and point the redirect layout to a mobile-friendly layout:

```yaml
layout: pos
useTabletMode: true
provider: y2
customerRedirectLayout: mobile
```

### FAQ

<details>

<summary><strong>Where do I configure the extension in Live Store?</strong></summary>

Use **newpossettings**. Configure it at the **global**, **country**, or **store** level. Live Store does not support this extension at the register level.

</details>

<details>

<summary><strong>Which URL should I use for <code>endpoint</code> and <code>apiEndpoint</code>?</strong></summary>

Use the `https://app.neostore.cloud/api/<tenantId>/external/livestore` base and replace `<tenantId>` with your tenant ID in The Wallet Crew.

If your project uses a different environment (staging, QA, or a custom domain), use the base URL provided by The Wallet Crew during setup.

</details>

<details>

<summary><strong>Can I reuse the same API key for test and production?</strong></summary>

Avoid it. Use separate API keys per environment. Rotate keys if you suspect they were exposed.

</details>

<details>

<summary><strong>Live Store redirects, but I end up on an error page. What should I check?</strong></summary>

Start with the basics. Confirm the `endpoint` URL is reachable from the Live Store network. Confirm the `X-API-KEY` header is present and correct. Then confirm the Cegid Retail Y2 connector is enabled in The Wallet Crew and can reach your Y2 services.

</details>


# Configure the Cegid Retail Y2 connector

Configure the Cegid Retail Y2 connector for Apple Wallet and Google Wallet, including credentials, rate limits, caching, receipts, and real-time updates.

Configure the Cegid Retail Y2 connector for Apple Wallet and Google Wallet. It supports customer accounts, loyalty cards, wallet benefits, and optional receipt journeys.

Cegid Retail Y2 can run in cloud or on-premise environments. Customer data from an enrolment form is stored in Cegid, then used in wallet passes.

### What the Cegid Retail Y2 connector supports

The connector creates and updates customer profiles through Cegid Y2 web services. It can also display loyalty data, vouchers, gift cards, and sales documents in wallet journeys.

Receipt configuration and Business Notifications are optional. Business Notifications support near real-time wallet refreshes after eligible Cegid events.

<details>

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

* A retail brand creates customer accounts from a loyalty enrolment form.
* An in-store purchase updates a loyalty balance and refreshes the wallet pass.
* Customers open a receipt or available voucher from a wallet journey.

</details>

### Cegid Retail Y2 connector requirements

Create a dedicated Cegid Retail Y2 service user for The Wallet Crew. Grant only the web-service permissions and data access required by the intended wallet journeys.

{% hint style="warning" %}
Activate chronos for stores attached to this user. Without them, background operations can fail, including loyalty updates and receipt generation.
{% endhint %}

The service user password must remain valid. Exempt this account from password expiry where permitted. Otherwise, track expiry and update the connector before access expires.

### Configure Cegid Retail Y2 connection settings

Open **Data & Integrations → CRM → Cegid Y2 → Configuration** in the admin portal. Enter all connection settings, then select **SAVE**.

| Field           | Value                                                                                                                            |
| --------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| **Service URL** | Base URL hosting the Y2 WCF services. A trailing `/` is added when missing. Example: `https://your-cegid-server.example.com/Y2/` |
| **DatabaseId**  | Cegid Y2 database name. This is the WCF `DatabaseId` connection parameter.                                                       |
| **User Name**   | Dedicated Cegid Y2 service-user name.                                                                                            |
| **Password**    | Password for the dedicated service user.                                                                                         |

<figure><img src="/files/NjOTqRhjiR6QiM5cz9Zu" alt="Enter the database identifier used by the Cegid Retail Y2 web services." width="563"><figcaption></figcaption></figure>

Settings apply immediately after saving. No service restart is required.

### Configure optional Cegid receipts

Receipt configuration is optional. Configure it only when wallet journeys need Cegid-generated receipts.

Receipt settings control documents generated through the Cegid integration. Leave **TemplateId** empty to use the Cegid default template.

| Field          | Value                                                           |
| -------------- | --------------------------------------------------------------- |
| **TemplateId** | Cegid receipt template identifier, such as `ZDE`.               |
| **Duplicate**  | Requests a duplicate of an issued receipt. Disabled by default. |

### Configure Cegid API rate limiting

Cegid applies a request ceiling over a rolling five-minute window. This capacity applies to the full Cegid environment, not just The Wallet Crew.

Other applications can consume the same request capacity. Set the limit below the Cegid ceiling after accounting for their expected traffic. Keep rate limiting enabled to avoid Cegid `429 Too Many Requests` responses during traffic spikes.

| Cegid plan |               Cegid ceiling | Recommended limit |
| ---------- | --------------------------: | ----------------: |
| Advance    |  5,000 requests / 5 minutes |             4,980 |
| Dedicated  | 20,000 requests / 5 minutes |            19,600 |

Use **Enable rate limiting** to control the limiter. Set **Max requests per 5 minutes** to the capacity allocated to The Wallet Crew, not the full Cegid plan limit. The default is enabled with a limit of `4980`.

When the limit is reached, The Wallet Crew throttles requests before Cegid rejects them. This reduces failed customer-facing operations.

### Configure Cegid API caching

Caching reduces repeated Cegid calls and helps stay within the request limit. All cache durations use seconds. Set a value to `0` to disable cache for that service.

| Setting             | Cached data                | Recommended starting point    |
| ------------------- | -------------------------- | ----------------------------- |
| **Customer**        | Customer profiles          | 60–300 seconds                |
| **Loyalty**         | Points, tiers, and cards   | 60–300 seconds                |
| **Sale Documents**  | Receipts and order history | Confirm freshness needs first |
| **Cash Operations** | Vouchers and gift cards    | Confirm freshness needs first |

Validate the chosen durations against the expected data freshness. Shorter values increase Cegid traffic. Longer values can delay visible updates.

### Configure optional real-time Business Notifications

Business Notifications are optional. They allow Cegid Retail Y2 to notify The Wallet Crew about relevant events. This can refresh wallet data after loyalty, purchase, or order activity.

{% hint style="warning" %}
Cegid Retail Y2 supports only one Business Notification listener. Enabling this feature replaces the listener configured in Cegid. Confirm ownership with the Cegid administrator first.
{% endhint %}

Enable **Listen to business notification** only after this confirmation. Then enter the dedicated Business Notification User credentials:

* **Business Notification User Name**
* **Business Notification Password**

Leave this setting disabled when another system must retain the Cegid listener.

### Configure multiple Cegid Retail Y2 connections

The configuration page exposes the default Cegid connection only. Some retailers use separate Cegid databases for brands or regions.

When multiple connections exist, the page displays an information banner. Adding, removing, or editing non-default connections requires The Wallet Crew support.

### Validate the Cegid Retail Y2 connector

After saving, validate the connection with a controlled customer record:

1. Create or retrieve a customer through an enrolment flow.
2. Confirm the profile appears in Cegid Retail Y2.
3. Confirm the expected loyalty data or benefit appears on the wallet pass.

For real-time notifications, update loyalty data in Cegid and confirm the wallet data refreshes. Monitor Cegid request capacity during the validation period.

### Cegid Retail Y2 field mapping and APIs

The connector maps standard customer fields, consent values, and loyalty data by default. Review [Cegid Retail Y2 fields mapping](/connectors/pos/cegid/cegid-retail-y2-fields-mapping) before configuring an enrolment form.

For the web services used by the connector, including customer, loyalty, cash operations, sale documents, and Business Notifications, see [Cegid Retail Y2 APIs](/connectors/pos/cegid/cegid-retail-y2-apis).

### FAQ

<details>

<summary><strong>Does The Wallet Crew support Cegid Retail Y2 cloud and on-premise?</strong></summary>

Yes. The connector supports both deployments when The Wallet Crew can access the required Cegid Y2 web services.

</details>

<details>

<summary><strong>Why does the Cegid Retail Y2 connector stop working after a period?</strong></summary>

An expired Cegid service-user password is a common cause. Renew the password in Cegid, then update the connector configuration.

</details>

<details>

<summary><strong>Should Cegid API rate limiting be disabled?</strong></summary>

No. Keep it enabled in production. Allocate a limit below the Cegid ceiling, accounting for other applications in the same environment.

</details>

<details>

<summary><strong>Are Cegid receipts and Business Notifications required?</strong></summary>

No. Configure receipts only for receipt journeys. Enable Business Notifications only when real-time Cegid events are required.

</details>

<details>

<summary><strong>Can several Cegid Retail Y2 databases be configured from this page?</strong></summary>

No. This page manages the default connection only. Contact The Wallet Crew support for a multi-connection setup.

</details>


# Cegid Retail Y2 fields mapping

### Customer and loyalty data synchronization

Creation and update of customer account and loyalty cards in Y2 via the registration forms.

Field mapping: Here is the list of fields that are available by default in the connector:

```
Wallet Crew fields     Y2(WebService) fields
--------------------------------------------------------------------------
email                  EmailData.Email
consents_email         EmailData.EmailingAccepted
phoneNumber            PhoneData.CellularPhoneNumber
isProspect             IsProspect
firstName              FirstName
lastName               LastName
sex                    Sex
title                  TitleId
advisor                SalesPersonId
storeId                UsualStoreId
birthDate              BirthDateData
address                AddressData.AddressLine1
streetNumber           AddressData.AddressLine2
postcode / zipCode     AddressData.ZipCode
city                   AddressData.City
country                AddressData.CountryId
nationality            NationalityId
consents_email         OptinEmail(true = BrandOnly, false = DoNotUse)
consents_post          OptinPostal(true = BrandOnly, false = DoNotUse)
consents_sms           OptinMobile(true = BrandOnly, false = DoNotUse)
consents_emailReceipt  EmailData.SendReceiptByMail
```

If you want additional fields, contacting your Wallet Crew administrator. The labels and values of the multiple-choice fields have to be filled in and located in The Wallet Crew BackOffice. The same applies to consents and other legal texts.

### Mapping personalization

It is possible to customize mapping with a custom javascript script. The script requires 2 methods : MapFromY2 and MapToY2. You will find below the minimal script to use the custom mapping

```js
// file server/scripts/y2.mapping.js

/**
 * Method used to convert information from the wallet crew data model to Y2 data modal.
 * This method will be invoked each time a customer is created or updated to Y2
 *
 * This method should be implemented if you want to send specific data to Y2
 *
 * @param account dictionary of data coming from the wallet crew
 * @param data Y2 customer data modal as defined in the CustomerWcfService
 */
const mapToY2 = function (account, data) {};

/**
 * Method used to convert information from Y2 to neostore.
 * This method will be invoked each time a customer is retrieved and displayed within the wallet crew :
 * when editing an existing customer through an enrolment form or when displaying information on a pass
 *
 * @param data Y2 customer data modal as defined in the CustomerWcfService
 * @param account dictionary of data to set within the wallet crew
 */
const mapFromY2 = function (data, account) {};

export default function (context) {
  context.register("extensions.cegid.y2.mapper", {
    MapToY2: mapToY2,
    MapFromY2: mapFromY2,
  });
}
```

Y2 data model is defined like this : ![cegid\_retail\_y2\_fields\_mapping\_1.png](/files/ZEqTYzLbfo7HGzxeOdXp)

#### Recipes

**Y2 Free texts - YTC\_TEXTELIBRE**

Within Cegid it is possible to define up to 3 free text, they are stored in columns `YTC_TEXTELIBRE1`, `YTC_TEXTELIBRE2`, `YTC_TEXTELIBRE3`. Values are accessible using `UserDefinedTexts` property.

Mapping could be done like this :

```javascript
// correct Id value should be replace - 2 times in mapToY2 and 1 time in mapFromY2
// Id : 0 => YTC_TEXTELIBRE1
// Id : 1 => YTC_TEXTELIBRE2
// Id : 2 => YTC_TEXTELIBRE3

const mapToY2 = function (account, data) {
  // other field mapping

  const comment = account["comment"];
  if (comment) {
    data.UserDefinedTexts = [
      ...(data.UserDefinedTexts || []).filter((udt) => udt?.Id != 0),
      { Id: 0, Value: comment },
    ];
  }
};

const mapFromY2 = function (data, account) {
  // other field mapping

  account["comment"] = (data.UserDefinedTexts || []).find(
    (udt) => udt?.Id == 0,
  )?.Value;
};
```

**Y2 Free table - YTC\_TABLELIBRETIERS**

Within Cegid it is possible to define up to 10 values in free table (Table libre in french), they are stored in columns `YTC_TABLELIBRETIERS1`, `YTC_TABLELIBRETIERS2`, `YTC_TABLELIBRETIERS3`, `YTC_TABLELIBRETIERS4`, `YTC_TABLELIBRETIERS5`, `YTC_TABLELIBRETIERS6`, `YTC_TABLELIBRETIERS7`, `YTC_TABLELIBRETIERS8`, `YTC_TABLELIBRETIERS9`, `YTC_TABLELIBRETIERSA`. Values are accessible using `UserDefinedData` property.

Be careful Cegid WebServices as a gap of 1 between name on the database and name on the web service.

Mapping could be done like this :

```javascript
// Y2 as a gap of 1. UserDefinedTable0Value is YTC_TABLELIBRETIERS1, etc.
/*
 * UserDefinedTable0Value => YTC_TABLELIBRETIERS1
 * UserDefinedTable1Value => YTC_TABLELIBRETIERS2
 * UserDefinedTable2Value => YTC_TABLELIBRETIERS3
 * UserDefinedTable3Value => YTC_TABLELIBRETIERS4
 * UserDefinedTable4Value => YTC_TABLELIBRETIERS5
 * UserDefinedTable5Value => YTC_TABLELIBRETIERS6
 * UserDefinedTable6Value => YTC_TABLELIBRETIERS7
 * UserDefinedTable7Value => YTC_TABLELIBRETIERS8
 * UserDefinedTable8Value => YTC_TABLELIBRETIERS9
 * UserDefinedTable9Value => YTC_TABLELIBRETIERSA
 */

const mapToY2 = function (account, data) {
  // other field mapping

  const preference = account["preference"];
  if (preference) {
    data.UserDefinedData = {
      ...(data.UserDefinedData || {}),
      UserDefinedTable1Value: preference,
    };
  }
};

const mapFromY2 = function (data, account) {
  // other field mapping

  account["preference"] = data.UserDefinedData?.UserDefinedTable1Value;
};
```


# Cegid Retail Y2 APIs

Overview of the Cegid Retail Y2 web services and business notifications used by The Wallet Crew connector.

This page lists the Cegid Retail Y2 services used by The Wallet Crew connector. It explains what each service does, why it matters, and which methods are called.

For connector setup, see [Connect with Cegid Retail Y2](/connectors/pos/cegid/connect-with-cegid-retail-y2). For customer field synchronization, see [Cegid Retail Y2 fields mapping](/connectors/pos/cegid/cegid-retail-y2-fields-mapping).

### At a glance

The Wallet Crew connects to Cegid Retail Y2 in real time through APIs and business notifications. Each service supports a specific wallet use case.

* **Customer** supports profile search, creation, update, and consent management. It is used to expose customer data in wallet journeys.
* **Cash Operations** exposes available vouchers and gift cards. It is used to display wallet benefits and stored value.
* **Loyalty** supports loyalty card creation and loyalty data retrieval, such as card details or points.
* **Sale Documents** exposes receipts and sales documents. It is used for receipt display and click-and-collect related journeys.
* **Business Notifications** sends events related to loyalty, purchase, or order activity. It is used to refresh wallet data and trigger push notifications in real time.

<details>

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

* A brand creates or updates a customer from an enrolment form. The Wallet Crew writes the profile back to Cegid Retail Y2.
* A loyalty card is created in Cegid Retail Y2, then displayed in Apple Wallet or Google Wallet with current balances or benefits.
* A recent purchase triggers receipt retrieval or PDF generation, so the document can be exposed in a wallet journey.

</details>

### How the integration works

The Wallet Crew uses two integration patterns with Cegid Retail Y2. Web service calls retrieve or update data on demand. Business notifications signal events that should trigger a refresh or a wallet notification.

In practice, customer and loyalty services support enrolment and card lifecycle. Cash operation and sales document services expose benefits and transaction data. The sales report endpoint generates receipt PDFs when a document file is needed.

### Services used by The Wallet Crew

#### Customer

The customer service supports profile lookup, creation, update, and consent synchronization. It is the foundation for account-linked wallet journeys.

**Endpoint:** `CustomerWcfService.svc`

**Methods used**

* `SearchCustomerIds` searches customer records, typically by email.
* `UpdateCustomer` updates an existing customer profile.
* `AddNewCustomer` creates a new customer in Cegid Retail Y2.

#### Cash Operations

The cash operations service exposes vouchers and gift cards attached to a customer. This makes stored value or available benefits available to wallet experiences.

**Endpoint:** `CashOperationsWcfService.svc`

**Methods used**

* `GetCustomerAvailableBons` retrieves available vouchers or gift cards for a customer.

#### Loyalty

The loyalty services manage loyalty cards and program data. They are used to create cards, retrieve card details, and determine which programs are available.

**Endpoints:** `LoyaltyWcfService.svc` and `LoyaltyEngineLoyaltyEngineService.svc`

**Methods used**

* `GetCustomerCards` returns loyalty cards linked to a customer.
* `GetLoyaltyCard` returns the details of a specific loyalty card.
* `CreateLoyaltyCard` creates a new loyalty card in Cegid Retail Y2.
* `GetCardCreationActiveProgramsOnStore` returns the loyalty programs available for a store.

#### Sale Documents

The sale document service provides access to transaction records. It is used for wallet use cases that depend on receipts or click-and-collect related documents.

**Endpoint:** `SaleDocumentService.svc`

**Methods used**

* `GetByKey` retrieves a specific sales document by key.
* `GetHeaderList` retrieves a list of recent sales documents.

#### Sales Report

The sales report service generates a receipt PDF. It is used when a rendered document is needed instead of raw sale document data.

**Endpoint:** `SalesExternalReport` (REST)

**Receipt PDF generation flow**

The receipt flow has three steps. First, `generatedocument` starts the PDF generation. Then `poll` checks whether the file is ready. Finally, `download` retrieves the generated PDF.

**Methods used**

* `generatedocument` starts a new PDF generation.
* `poll` checks whether the PDF is available.
* `download` downloads the generated PDF.

#### Employee

The employee service retrieves store staff data. It is mainly used when a wallet layout needs to display an advisor or salesperson.

**Endpoint:** `EmployeeSalespersonsService.svc`

**Methods used**

* `GetListDetail` returns the list of advisors for a store.

#### Business Notifications

Business notifications keep wallet data fresh without waiting for a manual refresh. They let The Wallet Crew react to events such as loyalty updates, purchases, or orders.

**Endpoint:** `BusinessNotificationSubscriptionService.svc`

**Methods used**

* `GetActive` lists active subscriptions.
* `Update` updates an existing subscription.
* `Create` creates a new subscription.
* `Delete` removes an existing subscription.

### Why these APIs matter

Together, these services let The Wallet Crew keep customer profiles, loyalty data, benefits, and transaction records aligned with Cegid Retail Y2. That alignment is what makes wallet passes feel current, reliable, and operationally useful.

### FAQ

<details>

<summary><strong>Does the connector rely only on notifications?</strong></summary>

No. The connector uses direct API calls to read and write data, and business notifications to react to events in near real time.

</details>

<details>

<summary><strong>Which service is used for vouchers and gift cards?</strong></summary>

`CashOperationsWcfService.svc` is used for that purpose through `GetCustomerAvailableBons`.

</details>

<details>

<summary><strong>Which service generates receipt PDFs?</strong></summary>

`SalesExternalReport` generates the PDF. `SaleDocumentService.svc` is used separately to retrieve sale document data and document lists.

</details>


# Newstore


# Openbravo


# Shopify POS

Configure The Wallet Crew scanner tile in Shopify POS to scan digital wallet passes, identify customers, and verify pass details at checkout.

## Scan wallet passes with Shopify POS

The Wallet Crew scanner tile adds wallet-pass scanning to Shopify POS. Store staff can scan a customer's digital pass during checkout. Shopify POS then identifies the customer and displays the available details.

This guide covers tile setup, permissions, and in-store validation. For wallet enrolment and online “Add to Wallet” buttons, see [Shopify](/connectors/e-commerce/shopify).

<details>

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

* A loyalty member presents a wallet pass at checkout for identification.
* Store staff scan a pass before applying member-specific benefits.
* A retail team confirms the pass details before completing a transaction.

</details>

### Prerequisites

The tile requires:

* Shopify POS installed on the store device.
* The Wallet Crew app available in Shopify POS.
* Camera access enabled for Shopify POS.
* A test pass with a visible QR code.

{% hint style="info" %}
The POS device must have an available camera. Camera permissions are managed by the device operating system.
{% endhint %}

### Add the scanner tile

The tile gives store staff a direct entry point from the Shopify POS home screen.

{% stepper %}
{% step %}

#### Open tile management

1. Open **Shopify POS** on the store device.
2. Select **Settings**.
3. Select **Manage tiles**.
   {% endstep %}

{% step %}

#### Add The Wallet Crew tile

1. Select **Add tile**.
2. Select **App**.
3. Select **The Wallet Crew** from the available apps.
   {% endstep %}

{% step %}

#### Enable camera access

1. Return to the Shopify POS home screen.
2. Open the **The Wallet Crew** tile.
3. Allow camera access when prompted.
   {% endstep %}
   {% endstepper %}

### Scan and verify a pass

Scanning validates that the tile can read a pass during a real checkout flow.

1. Open the **The Wallet Crew** tile in Shopify POS.
2. Point the POS camera at the pass QR code.
3. Confirm Shopify POS identifies the customer.
4. Confirm the expected customer details appear before checkout.

Test with an active pass on a physical device. A printed code may not reproduce the screen brightness and focus conditions of a live scan.

### Troubleshooting

#### The Wallet Crew tile is unavailable

Confirm that The Wallet Crew appears in the Shopify POS app list. If it does not, verify the app installation and the Shopify POS account used on the device.

#### The camera does not open

Check the device-level camera permission for Shopify POS. Close and reopen the app after granting access.

#### The pass does not scan

Clean the camera lens and increase the pass screen brightness. Keep the QR code fully visible inside the scanner frame. Test with another active pass to isolate a pass-specific issue.

## FAQ

<details>

<summary><strong>What does the scanner tile do?</strong></summary>

The tile scans a customer's digital wallet pass in Shopify POS. It identifies the customer and displays their details for verification at checkout.

</details>

<details>

<summary><strong>Is camera access required?</strong></summary>

Yes. Shopify POS needs camera access to scan the pass QR code. Grant the permission when opening the tile.

</details>

<details>

<summary><strong>How should the setup be tested?</strong></summary>

Use an active pass displayed on a phone. Scan its QR code and confirm the correct customer details appear in Shopify POS.

</details>


# Square




---

[Next Page](/llms-full.txt/1)

