Onboarding
CLI Init
One-shot org bootstrap + agent wallet + starter API key from a single email + client-derived addresses
POST
CLI Init
The public unauthenticated endpoint that powers the
No
The response also sets
@axon402/init onboarding helper. One round-trip creates a Supabase auth user, bootstraps a browser-mode org + vault wallet + agent wallet + starter mandate, and mints a wallet-scoped starter API key.
This endpoint is one-shot per email — it is the first-run bootstrap, not a general key-issuance API. For ongoing operator keys (org-wide, rotatable, scoped), use the authenticated POST /v1/api-keys route. The durable
@axon402/cli (axon-op) consumes those keys.Request
Authorization header. The endpoint is intentionally anonymous.
Required Fields
Optional Fields
Example Request
Response
Success (201 Created)
Fields
Error Responses
400 VALIDATION_ERROR examples
The exactmessage field varies by which check fired:
email is required and must be a valid address ≤254 charsvault_address must be a valid Ethereum addressroot_address must be a valid Ethereum addressvault_address must equal root_address in browser modeagent_address must be a valid Ethereum addressagent_derived_path must match m/44'/60'/0'/0/N where N >= 1agent_address must differ from vault_address (vault is index 0; agents start at index 1)org_name must be ≤64 chars
409 CONFLICT shape
429 RATE_LIMITED shape
Retry-After: 3421 as an HTTP header, per RFC 7231.
Behavior
When the request is valid and within the rate limit, the endpoint performs the following side effects in order:-
Per-IP rate limit check. Distributed via the Postgres
rate_limitstable so it survives Cloud Run horizontal scaling. 10 events per hour perreq.ip(Cloud Run trust-proxy hop is stripped, soreq.ipis the real client). -
Supabase auth user creation. Calls
auth.admin.inviteUserByEmail(email, { data: { cli_origin: true, signup_source: 'cli_init_v1' } }). This creates the user as unconfirmed AND dispatches a confirmation email using the Supabase project’s Site URL + email template. Thedashboard_urlreturned in the response is informational — the actual link in the email is generated server-side by Supabase GoTrue. -
Org + vault bootstrap. Calls the shared
bootstrapBrowserOrgForUserhelper (the same one the dashboard uses for browser-mode signups) with the user-providedvault_address. Creates the organization, the vault wallet at HD index 0, and the owner membership. -
Agent wallet + mandate creation. Calls
createAgentwith thewallet_overridebranch so the server skips its own derivation (impossible in browser signing mode — there’s no server-side mnemonic). Creates the agent wallet at the user-providedagent_derived_pathindex, with a starter mandate: -
API key minting. Generates a
axon_sk_*wallet-scoped key bound to the agent wallet (not the vault). Inserts the HMAC-SHA256 hash into theapi_keystable; the plaintext is returned exactly once. The key has scopes["read", "write"]. -
Auth user rollback on failure. If steps 3, 4, or 5 throw, the endpoint best-effort calls
auth.admin.deleteUser(userId)to undo step 2. Otherwise every helper failure would leak an orphanedauth.usersrow that locks the email out of future signups.
Security notes
- The mnemonic is generated client-side and never sent to the server. Only the derived addresses are POSTed. This is the browser-mode invariant, and it’s load-bearing: in production the server has no master mnemonic and cannot derive addresses on its own.
- The endpoint is rate-limited by IP, not by token, because there is no token. Spam protection is a single line of defense — the
rate_limitsPostgres table — andS-2in the audit backlog tracks tightening this further. - Email enumeration is possible: the 409 vs 201 distinction tells an attacker whether a given email is registered. The audit (
S-3) tracks this trade-off; we accepted it because flattening to a generic 200 would break the synchronous-key UX the CLI depends on. - HMAC-SHA256 with server-side pepper is used for storing API key hashes. A database leak alone is not enough to brute-force or rainbow-table the keys; the attacker also needs the pepper, which lives in Cloud Run’s secret store.
See also
@axon402/initCLI Reference — the canonical caller of this endpoint@axon402/cli— the durable operator CLI for everything that comes after the first wallet- POST /v1/api-keys — authenticated route for minting org-wide tenant keys
- Bootstrap Organization — the dashboard’s authenticated equivalent (same helper underneath)
- Error Codes — full reference for
codefield values