Dashboard

The tenant dashboard at /dashboard is the web UI for everything the CLI does, minus the typing. Open it, paste your API key when asked — the key is kept in the browser, and the sponsor token is never stored.

What it’s for:

  • Usage — checks, decisions, and receipt volume for the tenant.
  • Billing — the free-tier meter (1,000 receipts/month), billing status, and whether a payment method is on file. Sign in with your API key, or click Email me a sign-in link for a one-time 15-minute link — no key pasting. Add payment method opens Stripe’s hosted billing portal (card details never touch Writ); Stripe returns you to the dashboard, which confirms the card and lifts the 402 payment_required gate.
  • Policy editor — set per-verb modes (allow, deny, require_grant, step_up) without the CLI. Changes take effect immediately.
  • Team invites — create invite codes; see who holds a key on the tenant.
  • Live audit log — the same stream as ./writ stream, in the browser. Filter by verb, decision, or principal.
  • Kill switch — revoke or reinstate a principal. Revocation takes effect on the next check.

The API behind it: POST /v1/auth/magic-link ({email}) emails the single-use link and always returns 200 for unknown emails; GET /v1/auth/verify?token=... burns the token and sets an HttpOnly signed session cookie (24h) bound to the tenant; POST /v1/billing/portal accepts the API key or that session cookie and returns the Stripe portal URL.

Anything the dashboard can do, the API and CLI can do — it’s a convenience layer, not a separate system. Grants and revocations still require the sponsor token, which you paste per action.