BYOK graduation: an agent goes from nothing to standard tier with zero humans
2026-08-27
LOCKSTEP TRACEABILITY MATRIX --- api_endpoints: [ "GET /v1/account/graduation", "POST /v1/account/graduate", "POST /v1/mcp/bootstrap", "GET /v1/mcp/bootstrap", ] sdk_methods_updated: [ "client.account.graduation()", "client.account.graduate()", "py: account.graduation()/graduate()", ] mcp_tools_updated: ["br_graduation_status", "br_graduate", "br_capabilities_query", "br_register (bootstrap)"] ---
What We Built
The founding vision — _tell any model to connect to brainstormrouter.com and it can register and get to work in a terminal, no browser ever_ — had exactly one dead end left: leaving the sandbox. POST /v1/register gives an agent an instant tenant and admin key, but the only path out of the $2/day community caps was email verification, which 503s in prod (no email provider configured) and whose fallback message literally told the agent to open a browser.
This ship replaces human verification with a machine-verifiable trust anchor: a provider API key that passes a live validation call. POST /v1/account/graduate live-tests the tenant's registered BYOK keys (all of them, until one passes an authenticated validation); on a pass, every community-tier key is promoted to standard tier ($5/day, daily request/token caps removed), the auth cache is busted, and a tenant.graduated evidence event records the provider + HTTP status that anchored the promotion. GET /v1/account/graduation is the self-describing criteria surface — an agent can ask "what do I need to do to level up" and get a machine-readable answer.
Alongside it: POST /v1/mcp/bootstrap, an unauthenticated MCP endpoint with exactly two tools (br_register, br_bootstrap_info) so pure-MCP agents onboard in-band; three fixed defects (below); and a sweep that makes every community-tier error message lead with a machine path — the dashboard is now the optional human fork, never the instruction.
Why It Matters
The customer is Claude and its peers. Every gateway competitor onboards agents into a browser signup at some point; BR now has a complete anonymous → sandbox → standard ladder where each rung is machine-verifiable. The graduation criterion is also sybil-resistant economics: provider keys cost real money, and post-graduation inference bills the agent's own provider account — so the platform's subsidy exposure stays bounded ($5/day metering, rpm and in-flight caps unchanged) while the agent's capability is uncapped.
How It Works
# 1. Register (anonymous, instant)
curl -X POST https://api.brainstormrouter.com/v1/register \
-d '{"tenant_name": "My Agent", "accept_tos": true}' -H "Content-Type: application/json"
# 2. BYOK
curl -X POST https://api.brainstormrouter.com/v1/providers \
-H "Authorization: Bearer br_live_…" -H "Content-Type: application/json" \
-d '{"provider": "anthropic", "api_key": "sk-ant-…"}'
# 3. Graduate
curl -X POST https://api.brainstormrouter.com/v1/account/graduate \
-H "Authorization: Bearer br_live_…"
# → { "graduated": true, "tier": "standard", "evidence": { "byok": { "provider": "anthropic", "status": 200 } } }
Strictness matters: graduation requires a NOTELESS testProviderKey pass with a numeric status — exactly 2xx or 405, both only reachable when the provider did NOT 401/403 the key. (405 is Anthropic's valid-key signal: its probe is OPTIONS /v1/messages, auth checked before method dispatch — verified live; a bare-2xx rule would have made Anthropic keys ungraduatable, caught in the live loop.) All active keys are tested (parallelism capped at 3, eligibility never sliced). Failures are classified (no_provider_keys / provider_auth_failed / provider_unreachable) with per-key results and recovery actions.
Abuse posture: per-tenant limiter (5/h), global daily brake (BR_GRADUATION_DAILY_CAP, default 200), register IP caps unchanged, promotion does not raise rpm/concurrency, one-graduation-per-tenant is structural (idempotent no-op once no community keys remain). Optional env-gated criteria: BR_GRADUATION_MIN_REQUESTS, BR_GRADUATION_MIN_REPUTATION.
Defects fixed en route
PUT /v1/billing/plan403'd every caller since it shipped — it gated on
apiKey.role, a field that does not exist on ResolvedApiKey. Now RBAC-only (config.write), and sandbox tenants get a 409 pointing at graduation instead of a plan flip that wouldn't lift their caps.
- Email-verify promotion never busted the auth cache — a promoted key kept
enforcing community caps for up to 30s. Both paths now share tier-promotion-service (promote → COMMIT → invalidate by key_hash).
- **
br_capabilities_querywas advertised (capability graph seed, docs) but not
registered on the MCP server** (-32602). Now a real tool sharing queryCapabilityGraph with GET /v1/capabilities.
Also: the registration flow was extracted to registration-service.ts so the MCP bootstrap tool inherits the same IP caps (5/h + 3 sandbox/day) — a 429 from br_register is the register limiter, not the bootstrap connection limiter (30/h). Root package.json is now "private": true (its name collides with the published SDK). Edge check: verified live that api.brainstormrouter.com serves real gateway responses to curl/python-httpx/urllib/node/empty UAs — no WAF UA gate exists.
Verification
pnpm checkgreen (format + tsgo + oxlint).pnpm buildgreen.pnpm exec vitest run: 34 tests across 8--config vitest.unit.config.ts
files — graduation-service (strict/weak-405/no-key/unreachable/fourth-key/idempotent), mcp-bootstrap (real McpServer handshake, tools/list=2, IP threading, 429-as-isError), verify-email cache regression, billing phantom-role + sandbox-409 regressions, register (unchanged — refactor guard), tool-manifest, event-map-coverage, registry.
- Live loop post-deploy: see the transcript appended below (§1.9 of the plan).
Lockstep Checklist
- [x] API Routes: 4 new capabilities registered in
_registry.ts(+ behavior overlays). - [x] TS SDK: generated resources + hand wrapper
account.graduation()/graduate(); tsc clean. - [x] Python SDK: generated + hand wrapper sync/async
graduation()/graduate(). - [x] MCP Schemas: manifest 116 → 119 (
br_graduation_status,br_graduate,br_capabilities_query); agents.json regenerated (119). - [x] Discovery surfaces: llms.txt (both copies), llms-agent-playbook.txt, openapi merged (529 paths), self-describing docs refreshed, public-counts 119.
- [x] Docs: new
docs/start/graduation.mdx+ nav + quickstart tip. (docs/concepts/graduated-trust.mdxdeliberately untouched — that page is Guardian's runtime degradation ladder, a different trust system.)
Live verification transcript
Executed 2026-08-27 against production (deploy.json commit cc3ebda41), curl only, default curl UA, zero browser:
0. GET /deploy.json → commit 52d64a8f3 (then cc3ebda41 after the 405 fix)
1. POST /v1/register (anonymous) → plan=sandbox, tier=community, scopes=[admin]
upgrade_paths order: [byok_graduation, email_verify, invite_code, claim_dashboard]
2. GET /v1/account/graduation → tier=community, criteria=[(verified_byok, false)], usage_today {req:0, tok:0}
3. POST /v1/account/graduate (no keys) → 403 graduation_criteria_unmet, reason=no_provider_keys,
how_to_satisfy={register, test_first, catalog}; body contains no "dashboard"
4. GET /v1/self → upgrade present: true; first suggestion: "graduate"
5. POST /v1/providers/test + /v1/providers → anthropic key: {valid:true, status:405}; stored 201
6. POST /v1/account/graduate → FIRST ATTEMPT 403 (bare-2xx rule rejected the 405) — fixed,
redeployed, then: 200 {graduated:true, tier:standard,
budget_usd_per_day:5, evidence:{byok:{provider:anthropic, status:405}}}
6b. POST /v1/account/graduate (again) → {graduated:false, already_graduated:true} (idempotent)
7. POST /v1/chat/completions model=auto → model=claude-haiku-4-5-20251001, "GRADUATED",
X-BR-Selection-Method: capability-matched, X-BR-Actual-Cost: 0.000038,
no X-BR-Tier header (community caps gone)
8. GET /v1/self (fresh cache) → upgrade present: false
9. GET /v1/mcp/bootstrap (no auth) → tools: [br_register, br_bootstrap_info]
POST initialize → serverInfo brainstormrouter-bootstrap 1.0.0
tools/call br_register → NEW tenant registered entirely over MCP (plan=sandbox, br_live_ key)
10. POST /v1/mcp/connect (authed) → br_capabilities_query works (was -32602): 1/11 nodes for "identity";
br_graduation_status → {already_graduated:true, tier:standard}
UA matrix (edge): default curl, python-httpx, python-urllib, node, and an empty UA all reach the real gateway (200 on /llms.txt, 401/400 from auth/validation on /v1/\*) — no WAF UA gate exists on api.brainstormrouter.com.