# Onboarding — Claude Code usage tracking → usage.byte56.com

Five steps. The /auth/register response carries everything you need for steps 3-5; you should not have to hand-craft env vars.

## Step 1: Get an invite code

Ask the admin (whoever runs this server) for a one-time invite code. If you ARE the admin and on the LAN, mint one with POST /auth/invite — LAN callers are auto-admin.

Admin / LAN-only:
```
curl -X POST -H "Content-Type: application/json" -d '{"count":1}' https://usage.byte56.com/auth/invite
```

## Step 2: Register and receive your token + setup payload

POST {email, invite_code, machine} to /auth/register. The response includes the token AND a fully-populated setup object covering all three delivery methods (powershell / bash / settings.json). Use that response directly — do not hand-craft env vars from memory.

```
curl -X POST -H "Content-Type: application/json" -d '{"email":"<your-email>","invite_code":"<one-time-code>","machine":"<this-machine-hostname>"}' https://usage.byte56.com/auth/register
```

> If you already registered before, use POST https://usage.byte56.com/auth/token (also requires the original invite_code as identity proof) to refetch the token + setup payload. Use POST https://usage.byte56.com/auth/rotate (auth: existing bearer) to swap to a new token.

## Step 3: Apply ALL SIX env vars — pick ONE delivery method

Claude Code's OTel exporter silently drops batches if any one of the six is missing. The /auth/register response gives you ready-to-paste blocks for each method; do not partially apply, do not merge.

Required vars (all six):
- CLAUDE_CODE_ENABLE_TELEMETRY
- OTEL_METRICS_EXPORTER
- OTEL_EXPORTER_OTLP_PROTOCOL
- OTEL_EXPORTER_OTLP_METRICS_ENDPOINT
- OTEL_EXPORTER_OTLP_HEADERS
- OTEL_RESOURCE_ATTRIBUTES

Delivery methods:
- **powershell** (windows) — user-environment — CLI + desktop both pick it up. Use `setup.methods.powershell.command` from /auth/register response.
- **bash** (macos, linux) — shell-export — append to ~/.zshrc or ~/.bashrc; CLI only. Use `setup.methods.bash.command` from /auth/register response.
- **settings_json** (windows, macos, linux) — ~/.claude/settings.json env block; CLI only — desktop app does NOT read this file. Use `setup.methods.settings_json.contents` from /auth/register response. ⚠ If the file already has an env block with a SUBSET of these vars, REPLACE the entire env block — do not merge. Partial merges are the #1 onboarding failure mode (UL-CO-T75).

## Step 4: Restart Claude Code

Quit any running Claude CLI / desktop process. The OTel SDK reads env vars at startup, so a process started before the vars were set will never pick them up — even if you set them correctly.

## Step 5: Verify with /validate

After running a short Claude Code session (any prompt that touches the API), confirm the server saw your machine.

```
curl -X POST -H "Authorization: Bearer <your-token>" -H "Content-Type: application/json" -d '{"host_name":"<this-machine-hostname>"}' https://usage.byte56.com/validate
```

**Success:** response.token === "ok" AND response.host_name_ever_seen === true. If host_name_ever_seen is false after ~60s of activity, GET /validate (no auth) for the full troubleshooting checklist.

## Is this machine tracking? (validation)

Always start here when asked "is this machine tracking?". Do NOT scrape the dashboard HTML or reverse-engineer /api/usage — those answer different questions. POST /validate has a single tracking_status field that is the answer.

Detect the host.name this machine is configured to send under:

```powershell
($env:OTEL_RESOURCE_ATTRIBUTES -split ',' | ? { $_ -match '^host\.name=' } | % { ($_ -split '=', 2)[1] })
```
```bash
echo "$OTEL_RESOURCE_ATTRIBUTES" | tr ',' '\n' | grep '^host\.name=' | cut -d= -f2
```

> Use the env var, not the system hostname — the env var is what Claude Code actually emits.

Then probe:

```
curl -X POST -H 'Authorization: Bearer <YOUR_TOKEN>' -H 'Content-Type: application/json' -d '{"host_name":"<host>"}' https://usage.byte56.com/validate
```

### tracking_status values

- **active** — Telemetry arrived in the last 5 minutes — working.
- **recent** — Last 5–60 minutes — working, just no fresh batch yet.
- **stale** — Last 1+ hour ago — Claude Code may have been quit.
- **host_never_seen** — Token valid but this host.name has never been ingested. OTEL_RESOURCE_ATTRIBUTES is wrong, or Claude Code was not restarted after env was set.
- **host_normalized** — Exact host.name not seen but a normalized variant was. response.hostname_match_candidates lists the names actually seen. Either match the env var or accept the existing recording.
- **no_host_supplied** — Token valid but you did not pass host_name. Re-call with one.
- **auth_invalid** — Token invalid or revoked — mint a new one (see additional_machine below).
- **no_token** — No Authorization: Bearer header.

### Key response fields

- tracking_status         — single-field summary (above)
- next_action             — literal one-line instruction tailored to the status
- recent_machines_for_token — every host.name the server has seen for this token in the last 24h. Spot normalization gotchas at a glance.
- recent_accounts_for_token — every Anthropic account the token has flowed to in the last 24h. Useful when a user has multiple accounts.
- tokens_24h_for_host     — how many tokens the server has recorded for this token + host combination

> Do not conflate "user" with "account". A single user (one user_tokens row, one bearer token) can emit tokens against multiple Anthropic accounts (personal Max + team seat).

## Setting up an additional machine (existing user)

When the user already has an account, do NOT call /auth/register — it will 409. Pick a path:

### **device_flow** (recommended)

Polling-handshake registration. Agent prints a code, user opens a browser and approves. No token-copying.

- 1. POST https://usage.byte56.com/auth/device/start  body: {"machine":"<hostname>"}  → returns device_code, user_code, resume_code, verification_url
- 2. Tell the user: open <verification_url>, sign in, enter <user_code>
- 3. POST https://usage.byte56.com/auth/device/poll   body: {"device_code":"..."}     → "pending" → "approved" (with token + setup payload)
- Fallback: if polling fails, agent can call POST https://usage.byte56.com/auth/device/redeem body: {"resume_code":"..."} once the user approves on the web.

### reuse_existing_token

When the user has the token in hand from a working machine.

- Find the token on a working machine: PowerShell [Environment]::GetEnvironmentVariable('OTEL_EXPORTER_OTLP_HEADERS','User'); macOS/Linux echo $OTEL_EXPORTER_OTLP_HEADERS; or grep OTEL_EXPORTER_OTLP_HEADERS ~/.claude/settings.json
- POST https://usage.byte56.com/auth/setup-additional  Authorization: Bearer <existing-token>  body: {"machine":"<hostname>"}  → setup payload

### email_password

Sign in to the dashboard via email + password, then mint setup. Useful when the user knows their account but not their token.

- POST https://usage.byte56.com/auth/login   body: {"email":"...","password":"..."}    → sets session cookie
- POST https://usage.byte56.com/auth/setup-additional  body: {"machine":"<hostname>"}  → setup payload (cookie auth)
- Or: open https://usage.byte56.com/, sign in, click "+ another machine" in the header.

## What usage.lan gives you

What usage.lan gives the user once telemetry is flowing.

### session_cap_nudges
Local takt-watch.mjs emits USAGE_STOP_SOON / USAGE_WRAP_UP / USAGE_LIMIT_HIT lines as the user approaches a session cap. Monitoring agents surface them as inline reminders so the user wraps up before being cut off.

### multi_account_weekly_pacing
For users with more than one Anthropic account (e.g. Personal Max + Team Premium), GET /api/me/pace recommends the right account based on weekly slack. takt-watch emits PACE_SWITCH from=X to=Y lines on transitions; ~/.takt/pace-current.json holds the latest verdict.
Endpoint: `GET https://usage.byte56.com/api/me/pace`

### forecasts
Predicts when a user will hit their 5h or weekly cap if they keep their current rate. Useful before kicking off a long task.
Endpoint: `GET https://usage.byte56.com/api/forecast`

### per_seat_usage
Per-user tokens against per-seat cap. Team plans are per-seat — admin aggregate views correctly show >100% when summed across all seats.
Endpoint: `GET https://usage.byte56.com/api/me/usage`

### limit_calibration
Dashboard buttons (Hit Limit / New Window) capture rate-limit ground truth from a Claude session, training per-account limit estimates.

### audit_trail
Every state-changing call writes to audit_events. Admins can answer "what did X look like before this change."

### webhooks
Per-account webhooks fire on limit_approaching / limit_hit / limit_predicted / telemetry_stale / window_reset / calibration_rejected events.
Endpoint: `https://usage.byte56.com/api/webhooks (admin)`

## Endpoints

- **register** — POST https://usage.byte56.com/auth/register
- **retrieve_token** — POST https://usage.byte56.com/auth/token
- **rotate_token** — POST https://usage.byte56.com/auth/rotate
- **login** — POST https://usage.byte56.com/auth/login
- **logout** — POST https://usage.byte56.com/auth/logout
- **set_password** — POST https://usage.byte56.com/auth/password/set (auth required)
- **admin_set_password** — POST https://usage.byte56.com/auth/password/admin-set (admin)
- **setup_additional** — POST https://usage.byte56.com/auth/setup-additional (auth required)
- **device_start** — POST https://usage.byte56.com/auth/device/start
- **device_poll** — POST https://usage.byte56.com/auth/device/poll
- **device_redeem** — POST https://usage.byte56.com/auth/device/redeem
- **device_verify_page** — GET https://usage.byte56.com/auth/device/verify
- **validate** — POST https://usage.byte56.com/validate
- **validate_checklist** — GET https://usage.byte56.com/validate
- **mint_invite_admin** — POST https://usage.byte56.com/auth/invite
- **dashboard** — GET https://usage.byte56.com/
- **pace** — GET https://usage.byte56.com/api/me/pace
- **forecast** — GET https://usage.byte56.com/api/forecast
- **usage_self** — GET https://usage.byte56.com/api/me/usage

## See also

- **validate** — https://usage.byte56.com/validate — companion endpoint for verifying a setup is working
