# Journey: Sign up and pay with crypto

Signup, crypto invoice issuance, the paywall, and signed settlement are each
real, but they are not one shipped customer funnel. Signup routes through
onboarding. `/billing` links to `/billing/crypto` without creating an invoice,
so it lands on the pending-issuance notice. Tests issue invoices through the BFF
API, then prove the paywall and settlement seams directly.

## Personas

- **New customer** — creates an account and completes onboarding before any
  protected billing surface.
- **Signed-in plan buyer** — needs a `pro` or `premium` invoice bound to the
  server price book and their user id.
- **Crypto payer** — receives an asset-specific non-custodial target and, for
  issued/less-decentralized rails, acknowledges the disclosure.
- **Settlement watcher/operator** — submits a signed on-chain confirmation and
  expects one plan mutation plus a verifiable receipt.

## Pre-conditions

- `/welcome` is public; protected `/billing` and `/billing/crypto` routes
  require an authenticated session.
- Production quoting requires a bound non-custodial payment runtime. Without
  one, methods are marked inactive and quote creation fails closed with `503`;
  no address is fabricated.
- The settlement receiver requires a configured HMAC secret and a bound receipt
  signer.
- A plan invoice derives amount/currency from the BFF price book. Client values
  may only echo that price and mismatches are rejected.

## Steps

### 1. Create the account and finish the auth handoff

`WelcomeAuthPanel` posts the real signup contract through the auth client,
tracks viewed/submitted/completed/failed funnel events, and sends new accounts
to the onboarding route. A sanitized `redirect` is preserved through onboarding;
signup does not immediately mint a paid entitlement or crypto invoice.

### 2. Reach the current billing boundary

`/billing` states that crypto is the wired rail and links to `/billing/crypto`.
That link carries no invoice id. Missing, malformed, over-length, unknown,
expired, cancelled, or confirmed invoices render `PendingIssuanceNotice` with
return/support actions. There is no customer upgrade tile that calls the quote
API and redirects with the issued id.

### 3. Issue an invoice through the BFF seam

`POST /v1/payments/crypto/quote` is session-optional, but only an authenticated,
plan-bearing quote can grant that purchaser a plan at settlement. It checks
crisis suppression, runtime availability, supported asset, tenant, canonical
plan price, and the issuance disclosure gate. Only after the provisioner returns
a real unique target does the BFF persist the pending invoice and return the web
DTO.

Tier-B/Tier-C or centrally issued assets require acknowledgement before quote
issuance. The rendered paywall independently asks for its visible legal
acknowledgement before revealing the already-issued target.

### 4. Render and pay the pending invoice

`/billing/crypto?invoice=<id>` fetches only a pending DTO, displays fiat and
chain amounts, expiry, disclosure version, trust tier, address/QR, copy, and
billing support. The asset picker changes visible radio/network choices, but the
page provides no `onChainSelected` callback; it does not re-quote or replace the
original invoice target.

The customer sends funds outside the app. The page does not poll invoice status
or display confirmation depth.

### 5. Confirm through the signed settlement receiver

The deploy-bound watcher posts exact raw JSON with timestamped HMAC, invoice,
transaction, block hash, and block height. The BFF rejects missing config,
invalid/stale signatures, malformed payloads, unknown invoices, and unavailable
receipt signing. A valid pending invoice becomes `confirmed`, receives an
Ed25519-signed receipt, and—when purchaser, plan, currency, and book price all
match—updates the persisted customer plan. Replay is acknowledged without
re-driving the grant.

This route does not publish a customer-facing
`payment.invoice.confirmed → payment.invoice.settled` event chain. Those bridge
contracts exist elsewhere, but the shipped BFF settlement path performs one
direct pending-to-confirmed transition.

### 6. Re-enter after settlement

A fresh profile read sees the upgraded plan, and a fresh invoice fetch reports
`confirmed`. The paywall loader intentionally refuses non-pending invoices, so
reopening the URL shows the generic “could not find invoice” pending notice and
never leaks the stale payment address. There is no success receipt view or
“Continue to the gated surface” handoff.

## Post-conditions

- A provisioned invoice is snapshot-durable, purchaser-scoped in member list
  reads, and never persisted before a real receiving target exists.
- A valid signed settlement stores chain facts and receipt, confirms the
  invoice, and conditionally updates the purchaser's plan.
- Re-delivery is idempotent and a confirmed address is no longer rendered as
  payable.
- The end-user signup → issue → pay → success/return journey remains incomplete
  despite strong API/paywall/settlement coverage.

## Failure modes

- **No invoice from `/billing`** — the primary customer link ends at
  `PendingIssuanceNotice`.
- **No payment runtime** — quote returns `503 payments_not_configured` and
  methods are inactive.
- **Crisis frame active** — quote returns `403 crisis_suppressed` before showing
  a payment prompt.
- **Price/disclosure mismatch** — quote fails closed before target issuance.
- **Invalid settlement** — status, tx id, receipt, and plan remain unchanged.
- **Below-book settlement** — money can confirm, but entitlement is withheld and
  the invoice is flagged for support.
- **No live status UI** — an already-open paywall does not notice settlement;
  only a new navigation changes what is rendered.
- **Picker ambiguity** — changing asset/network controls does not mutate the
  issued invoice.

## E2E coverage

- [`apps/oshun/web/e2e/auth-entry-flows.spec.ts`](../../apps/oshun/web/e2e/auth-entry-flows.spec.ts)
  covers signup/auth redirect and onboarding entry separately.
- [`apps/oshun/web/e2e/billing-index.spec.ts`](../../apps/oshun/web/e2e/billing-index.spec.ts)
  covers protected billing entry, rail links, support, and responsive targets.
- [`apps/oshun/web/e2e/billing-crypto-paywall.spec.ts`](../../apps/oshun/web/e2e/billing-crypto-paywall.spec.ts)
  issues deterministic E2E quotes over real HTTP, drives BTC/USDC paywall and
  disclosure states, posts signed settlement, reads the plan/ledger/receipt
  boundary, rejects bad settlements, and proves no stale address after confirm.
- [`apps/oshun/web/e2e/entitlements-aaa-bff.spec.ts`](../../apps/oshun/web/e2e/entitlements-aaa-bff.spec.ts)
  protects an adjacent entitlement gate, not the missing invoice-creation UI.
- **Coverage depth: partial.** The component seams are deep; provider watching,
  customer issuance, live status/success, and gated-surface return are absent.

## Per-view files touched

- [`customer/00-public/welcome.md`](../customer/00-public/welcome.md) — real
  signup and onboarding handoff.
- [`customer/09-account/billing.md`](../customer/09-account/billing.md) — rail
  entry and missing issuance join.
- [`customer/09-account/billing-crypto.md`](../customer/09-account/billing-crypto.md)
  — pending notice, disclosure, address, and support.
- [`shell/04-auth-session.md`](../shell/04-auth-session.md) — protected routes
  and post-settlement plan reads.

## Cross-references

- [`aaa-upgrade-entitlement-bounce.md`](./aaa-upgrade-entitlement-bounce.md) —
  adjacent tier gate/Studio handoff.
- [`onboarding-ten-steps.md`](./onboarding-ten-steps.md) — mandatory new-account
  continuation after signup.
- Sources: `WelcomeAuthPanel.tsx`, `app/billing/page.tsx`,
  `app/billing/crypto/CryptoPaywall.tsx`, `routes/domain-stubs.ts`, and
  `payments/settlement-route.ts` under `apps/oshun`.

## Open questions

- Which customer plan surface should create the quote, handle the issuance
  disclosure, and redirect to the pending invoice?
- Should the paywall poll/subscribe to status and expose the signed receipt plus
  a sanitized return target after confirmation?
- Should asset/network controls be removed for a fixed invoice or wired to an
  explicit cancel-and-requote flow?
- How should bridge-level confirmed/settled events compose with the direct BFF
  transition without double-granting entitlement?
