# First Hour
This guide mirrors the checked-in `examples/accrue_host` story in package-facing
terms. Your Phoenix app owns `MyApp.Billing`, routing, auth, runtime config,
and verification choices. Accrue owns the billing engine behind those public
boundaries. Read-only processor queries such as saved payment methods use
`Accrue.Billing.list_payment_methods/2` (and the host wrapper `MyApp.Billing.list_payment_methods/2` after `mix accrue.install`); see [`guides/telemetry.md`](telemetry.md) for the `[:accrue, :billing, :payment_method, :list]` span.
Server-side **Stripe Checkout** session creation uses **`Accrue.Billing.create_checkout_session/2`**
(and your host facade after install); telemetry is **`[:accrue, :billing, :checkout_session, :create]`**
— see [`guides/telemetry.md#billing-checkout-session-create`](telemetry.md#billing-checkout-session-create).
Customer Portal session creation is the parallel server-side helper for Stripe-hosted billing self-service.
Server-side **Stripe Customer Portal** session creation uses **`Accrue.Billing.create_billing_portal_session/2`**
(and your host facade after install); telemetry is **`[:accrue, :billing, :billing_portal, :create]`**
— see [`guides/telemetry.md#billing-billing-portal-create`](telemetry.md#billing-billing-portal-create).
## How to enter this guide
This guide is one **spine** with three **entry capsules** — pick where you are starting, then follow the same ordered story (deps → install → runtime → migrations → Oban → webhooks → admin → proof). Public wording and step order stay aligned with [`examples/accrue_host/README.md`](../../examples/accrue_host/README.md#proof-and-verification); when the spine or command vocabulary changes, update that README in the **same** pull request (**D-02**). Maintainer checklist (**INT-11**): same-PR capsule discipline lives in the contributor map [`scripts/ci/README.md`](../../scripts/ci/README.md) — search for **First Hour + host README capsule parity**.
For **maintenance posture** (when to stop speculative doc work, how friction is intake-gated), see [Maturity and maintenance](maturity-and-maintenance.md).
### Capsule H — Hex consumer
You already have a Phoenix app. Add Accrue to `mix.exs`, run `mix deps.get`, then `mix accrue.install …` and continue from **§ 1. First run** below (runtime config → migrations → Oban → webhook route → admin mount → subscription + proof).
### Capsule M — Monorepo clone
From the repository root: `cd examples/accrue_host`, run **`mix setup`**, start **`mix phx.server`**, then follow the numbered host README story (subscription → signed webhook → admin → `mix verify`) — the same Fake-backed arc this guide describes in package terms. **Sigra** is wired in the checked-in demo for convenience and reproducibility, not because production Accrue apps must use it.
### Capsule R — Evaluate / read-only
Shortest read-only path: clone the repo, `cd examples/accrue_host`, run **`mix verify`** or **`mix verify.full`**. For merge-blocking VERIFY-01 detail and Playwright entry points, use [**#proof-and-verification**](../../examples/accrue_host/README.md#proof-and-verification) in the host README when you need more than the bounded proof commands.
### Trust boundary (production vs demo)
Production apps integrate billing through host-owned **`Accrue.Auth`**; see [Auth adapters](auth_adapters.md) for adapter choices and wiring contracts. **Sigra** is optional: the demo uses it for deterministic organization billing and CI, not as a blanket production requirement. When you are not on Sigra, follow **Capsule H** and [Organization billing (non-Sigra)](organization_billing.md) for org-scoped Stripe customers. Demo-specific `mix.exs` and setup commands stay in [`examples/accrue_host/README.md`](../../examples/accrue_host/README.md).
When you are preparing a **real** deploy (not the demo loop), walk [Production readiness](production-readiness.md) once — it links the same guides in ship order without duplicating them.
## 1. First run
The first hour should end with one Fake-backed subscription, one signed webhook
proof, mounted admin inspection, and a focused verification pass.
### Install the packages
> **Hex vs `main`:** The version pins below mirror `accrue/mix.exs` and `accrue_admin/mix.exs` `@version` on the branch you are reading (usually `main` on GitHub). [Hex.pm](https://hex.pm/packages/accrue) / [Hex.pm/packages/accrue_admin](https://hex.pm/packages/accrue_admin) reflect what is published; use HexDocs when you need docs tied to the resolved Hex version.
1. The fenced `~>` pins below track the **Hex-published** SemVer line for the `@version` pair this branch ships with.
2. **`path:`** / monorepo installs must keep **`accrue`** and **`accrue_admin`** on the **same three-part `~>`** (lockstep trains).
3. Pre-1.0 **`~>`** minors may still ship breaking API changes—treat **`mix.lock`** as the production stability boundary, not semver intuition alone.
```elixir
defp deps do
[
{:accrue, "~> 1.0.0"},
{:accrue_admin, "~> 1.0.0"}
]
end
```
```bash
mix deps.get
mix accrue.install --billable MyApp.Accounts.User --billing-context MyApp.Billing
```
The checked-in host example is the canonical local evaluation loop:
```bash
cd examples/accrue_host
mix setup
mix phx.server
```
### Keep runtime config host-owned
Accrue raises `Accrue.ConfigError` when required setup is missing. Keep secrets
and environment-specific values in `config/runtime.exs`:
```elixir
import Config
config :accrue, :processor, Accrue.Processor.Fake
config :accrue, repo: MyApp.Repo
config :accrue, :webhook_signing_secrets, %{
stripe: System.get_env("STRIPE_WEBHOOK_SECRET", "whsec_test_host")
}
```
Run your database setup before boot:
```bash
mix ecto.create
mix ecto.migrate
```
Start Oban with the app so webhook dispatch and replay work end to end:
```elixir
children = [
MyApp.Repo,
{Oban, Application.fetch_env!(:my_app, Oban)},
MyAppWeb.Endpoint
]
```
### Mount the public billing boundaries
Add signed webhook ingest at `/webhooks/stripe` and keep the handler on the
public callback surface:
```elixir
defmodule MyAppWeb.Router do
use MyAppWeb, :router
import Accrue.Router
pipeline :accrue_webhook_raw_body do
plug Plug.Parsers,
parsers: [:json],
pass: ["*/*"],
json_decoder: Jason,
body_reader: {Accrue.Webhook.CachingBodyReader, :read_body, []}
end
scope "/webhooks" do
pipe_through :accrue_webhook_raw_body
accrue_webhook "/stripe", :stripe
end
end
```
> **When this fails**
>
> - Raw body / parser order: [Troubleshooting — `ACCRUE-DX-WEBHOOK-RAW-BODY`](troubleshooting.md#accrue-dx-webhook-raw-body)
> - Missing signing secret: [Troubleshooting — `ACCRUE-DX-WEBHOOK-SECRET-MISSING`](troubleshooting.md#accrue-dx-webhook-secret-missing)
> - Webhook behind the wrong pipeline: [Troubleshooting — `ACCRUE-DX-WEBHOOK-PIPELINE`](troubleshooting.md#accrue-dx-webhook-pipeline)
> - **`mix accrue.install`** reruns / conflicts: [Upgrade — installer rerun behavior](upgrade.md#installer-rerun-behavior)
```elixir
defmodule MyApp.BillingHandler do
use Accrue.Webhook.Handler
@impl Accrue.Webhook.Handler
def handle_event(type, event, ctx) do
MyApp.Billing.handle_webhook(type, event, ctx)
end
end
```
Mount `accrue_admin "/billing"` behind your host auth boundary.
`AccrueAdmin.Router.accrue_admin/2` is the public router macro:
```elixir
import AccrueAdmin.Router
scope "/" do
pipe_through [:browser, :require_authenticated_user]
accrue_admin "/billing",
session_keys: [:user_token],
on_mount: [{MyAppWeb.UserAuth, :mount_current_user}]
end
```
### Prove the first subscription and webhook
Create the first subscription through the generated facade:
```elixir
user = MyApp.Accounts.get_user!(user_id)
{:ok, subscription} =
MyApp.Billing.subscribe(user, "price_basic", trial_end: {:days, 14})
```
For app-level tests, stay on supported helpers:
```elixir
use Accrue.Test
```
Then post one signed `customer.subscription.created` payload through
`/webhooks/stripe`, visit `/billing`, and confirm the mounted admin UI shows the
resulting billing state plus replay visibility.
Finish the guided path with the focused host proofs:
```bash
mix verify
```
`mix verify` is the focused tutorial proof suite. `mix verify.full` is the
CI-equivalent local gate that adds compile, assets, dev boot, regression, and
browser smoke after the first-run story is already clear. For the authoritative
merge-blocking command matrix, VERIFY-01, and Playwright entry points, see
[Proof and verification in the host demo README](../../examples/accrue_host/README.md#proof-and-verification).
## 2. Seeded history
`Seeded history` is for deterministic replay/history evaluation, not for the
main teaching path.
```bash
cd examples/accrue_host
mix setup
mix verify.full
```
Use it when you need replay-ready webhook states, browser smoke fixtures, or
other evaluation setup that should not become public integration guidance.
## 3. Focused verification
- `mix verify` proves the host-owned tutorial arc: installer boundary, first
subscription through `MyApp.Billing`, signed webhook ingest, mounted
`/billing` inspection, and replay visibility.
- `mix verify.full` is the CI-equivalent local gate for maintainers.
- `bash scripts/ci/accrue_host_uat.sh` is the repo-root wrapper around that
same full contract.
- `bash scripts/ci/accrue_host_hex_smoke.sh` is Hex smoke and stays separate
from the checked-in host demo.
- `mix accrue.install` remains the production setup command for your own host
app.
## 4. Rerunning mix accrue.install
Reruns refresh **pristine** generated files that still match the Accrue
fingerprint marker; **user-edited** generated files are skipped so local policy
changes are preserved. Unmarked existing files stay skipped unless you opt into
a narrow overwrite, and `--write-conflicts` writes reviewable artifacts under
`.accrue/conflicts/` instead of patching live files blindly — the same contract
as the upgrade guide. See
[Upgrade guide — Installer rerun behavior](upgrade.md#installer-rerun-behavior)
for the full installer rerun semantics.