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

# Marketing hub model: wallet passes, loyalty, and referrals behind one redirect

> How the /marketing surface family hangs together: the bare /marketing path as a redirect-only index, the wallet-passes console (issue, update, void, generation counter, idempotent issuance), the loyalty console (tiers, member ledger, point balance), the referrals console (per-contact codes, reward steps, leaderboard), and the note on when the redirect becomes a tiled hub.

# Marketing hub model

The dashboard's **Marketing** section is a family of consoles — wallet passes, loyalty, referrals, and the shared incentives engine — that together run your customer-facing reward surfaces. The bare `/marketing` route does not render a page of its own; it redirects to one sub-page. This document models that family as one design: why the index is a redirect today, what each console owns, and what changes when the family grows.

## 1. The hub redirect: /marketing is a route family, not a page

Visiting `/marketing` with no sub-path never renders a blank or a 404. The route family is defined so that any nav surface that lands on the bare path — command-K, deep links out of the campaign tooling — resolves cleanly to a real sub-page. Today the family holds one end-user program console that needs a landing, so `/marketing` redirects straight to **/marketing/referrals**. The redirect is deliberate product shape, not a placeholder: treat `/marketing` as the family's hub whose current tiling is a single tile.

Within the family, each console is independent and tenant-scoped:

| Console       | Sub-route                  | It owns                                                                           |
| ------------- | -------------------------- | --------------------------------------------------------------------------------- |
| Wallet passes | `/marketing/wallet-passes` | Issuing and managing Apple/Google Wallet passes for your contacts                 |
| Loyalty       | `/marketing/loyalty`       | The points-and-tiers program, per-member balance, and operator adjustments        |
| Referrals     | `/marketing/referrals`     | Programs, per-contact codes, conversions, and reward approval                     |
| Incentives    | `/marketing/incentives`    | The shared fulfillment ledger that redemptions and referral payouts route through |

All reads and writes stay inside your workspace — no console ever surfaces another tenant's programs, passes, or members.

## 2. Wallet passes console: issue, update, void

The wallet-passes console is the operator face of the pass lifecycle. A pass is a digital card — loyalty card, coupon, or event ticket — rendered for **Apple Wallet and Google Wallet** from one platform-agnostic content model. Its lifecycle is a strict state machine:

```text theme={null}
issue ──▶ active ──▶ (update)* ──▶ voided (terminal)
```

Four properties carry the design:

* **Issuance is idempotent.** Send an idempotency key and a retry returns the first issued pass instead of minting a duplicate, so a double-submit can never create two passes for one enrollment.
* **Update patches, never rewrites.** Only the fields you send change; explicit `null` clears a field. Every accepted update bumps the pass's `generation` counter by one.
* **The generation counter is the holder-refresh signal.** It starts at `0` at issue and increments on each update — compare it across polls to learn "something moved," and treat each bump as the trigger for telling Apple or Google Wallet to refresh the holder's copy.
* **Void is terminal.** A voided pass renders as expired in the holder's wallet; further updates return a conflict. A replacement is always a *new* pass.

The full state machine, the append-only ledger it projects from, and the delivery mechanics (save links, barcode formats, platform connection states) are documented in the [wallet pass lifecycle concept](/concepts/wallet-pass-lifecycle).

## 3. Loyalty console: tiers, member ledger, point balance

The loyalty console operates the points-and-tiers program whose balances project over your CDP event stream. Three views matter to an operator:

* **Tiers** — an ordered ladder keyed on lifetime earned points, with a required tier at threshold `0` so every member holds a tier from their first event. Tiers climb one-way: spending the balance never reduces lifetime points, so a member who redeems everything keeps their tier.
* **Member ledger** — a per-contact view that recomputes the spendable balance from the event history at read time: unexpired earn lots minus burns, plus the audit trail of every earn, burn, and adjustment behind it.
* **Point balance operations** — operator credits and debits are events in the same ledger. A redemption or debit runs under a per-contact lock, so concurrent spends serialize and a balance can never be overspent.

Earn rules (flat per-event grants and per-unit multipliers), the FIFO lot expiry model, and the event-sourced program revisions are the [loyalty program model](/concepts/loyalty-program-model).

## 4. Referrals console: codes, reward steps, leaderboard

The referrals console runs the program → code → conversion → reward chain end to end:

1. **Unique codes** — minting a code for a contact is mint-or-get: the same contact and program always return the same short, unambiguous code, so an "issue my link" action is safe to repeat. Each code's public face is the unauthenticated `/r/:code` redirect, which records the visit and tags the click-through with the attribution parameter.
2. **Reward steps** — a conversion lands as `pending` when signup creates the referred contact; nothing pays out until an operator approves it, which flips the conversion to `paid` and fulfills the reward through the incentives engine. `rejected` rows — fraud-guard rejects like same-IP visit-and-signup — never pay out.
3. **Leaderboard vs totals** — the leaderboard is a capped top-N ranking of codes by conversions; the totals view aggregates every code with no page-size limit. Never sum the leaderboard to drive a stat — it under-counts once a program has more than a page of referrers.

Reward types (billing credit, minted discount code, tracked manual payout), attribution carriers, and the fraud guards are the [referral program model](/concepts/referral-program-model).

## 5. Roadmap: when the redirect becomes a tiled hub

The redirect exists because the family has exactly one end-user program that needs a landing today. The product intent on the `/marketing` index is explicit: **when the family grows more sub-pages that deserve equal standing, the redirect is replaced by a hub that tiles them.** At that point `/marketing` stops forwarding and starts rendering — a hub page that presents the consoles side by side, the same way other hub surfaces present their families. Deep links to `/marketing/wallet-passes`, `/marketing/loyalty`, and `/marketing/referrals` are stable regardless; only the bare index changes behavior. Bookmark sub-routes, not the redirect.

## Related reading

* [Loyalty program model](/concepts/loyalty-program-model) — points, tiers, and the CDP ledger the loyalty console operates.
* [Referral program model](/concepts/referral-program-model) — program → code → conversion → reward, attribution, and payout gating.
* [Wallet pass lifecycle](/concepts/wallet-pass-lifecycle) — the pass state machine, generation counter, and idempotent issuance.
* [Incentives: catalog, ledger, and fulfillment](/concepts/incentives) — the shared engine that redemptions and referral payouts route through.
