Skip to content

Console

The console (/api/v1/console/*) is the self-service surface behind the bloonio_chat_admin_ssr portal (port 4318). An admin registers (via email OTP), owns a workspace, and manages its tenants, operators, members and invitations there — without ever touching the platform admin key.

Authentication is a console token (console_token, HS256, ~7 days, kind=tenant_admin), scoped through workspace memberships.

Registration is a two-step flow and always lands in a workspace — created from organization_name, or joined via an invite_token.

  1. StartPOST /console/register creates a PENDING account and sends an OTP by email. In local dev (ENV=local, SMTP not configured), the response returns the OTP in dev_otp.
  2. VerifyPOST /console/verify/registration validates the OTP, activates the account, creates (or joins) the workspace and returns a session.
  3. Resend (if needed) — POST /console/resend/registration-otp.
Fenêtre de terminal
curl $BASE_URL/api/v1/console/register \
-X POST -H "Content-Type: application/json" \
-d '{
"email": "admin@acme.com",
"password": "a-strong-passphrase",
"display_name": "Alex Admin",
"organization_name": "Acme Co"
}'

POST /console/login authenticates by email + password. The result is discriminated by redirect_to_mfa:

  • false — no second factor: the full session (with console_token) is returned.
  • true — a challenge_token and the mfa_factors list (for example ["email", "totp"]) are returned; you must complete a second factor.
Fenêtre de terminal
# 1. Login → returns a challenge_token when redirect_to_mfa = true
curl $BASE_URL/api/v1/console/login -X POST -H "Content-Type: application/json" \
-d '{"email":"admin@acme.com","password":"..."}'
# 2. Issue the second-factor OTP
curl $BASE_URL/api/v1/console/get/login-otp -X POST -H "Content-Type: application/json" \
-d '{"challenge_token":"chl_..."}'
# 3. Verify the OTP → full session
curl $BASE_URL/api/v1/console/verify/login-otp -X POST -H "Content-Type: application/json" \
-d '{"challenge_token":"chl_...","code":"123456"}'

The console’s protected routes then require the Authorization: Bearer <console_token> header.

The system console (/api/v1/console/system/*) is the platform-wide super-admin surface. An account is a super-admin when its is_system field is true — that is the only boolean that distinguishes an account.

It exposes, among other things, platform counters and global reads:

MethodPathRole
GET/system/fetch/statsCounters (workspaces, admins, tenants, operators, pending assignments)
GET/system/fetch/workspacesAll workspaces
GET/system/fetch/tenantsAll tenants (?status=active|suspended)
GET/system/fetch/adminsAll accounts (hashes excluded)
POST/system/suspend/tenantPlatform-wide suspension
POST/system/reactivate/tenantReactivation

Three ways to create an is_system account, from strongest to weakest:

  1. Deterministic seed (recommended). Set SYSTEM_ADMIN_EMAIL + SYSTEM_ADMIN_PASSWORD (and the optional SYSTEM_ADMIN_DISPLAY_NAME). At startup, the relay ensures a login-capable super-admin exists. Idempotent: an already-present account is promoted in place and its password is never reset. To run it on demand, without a redeploy:

    Fenêtre de terminal
    ENV=production python3 bash/seeds/bootstrap-system-admin.py \
    --email ops@bloonio.com --password '<strong-password>'

    Without --email/--password, the script falls back to SYSTEM_ADMIN_EMAIL / SYSTEM_ADMIN_PASSWORD from the .env selected by ENV.

  2. Allowlist. Emails in the SYSTEM_ADMIN_EMAILS CSV become is_system as soon as they register or log in (they choose their own password).

  3. Runtime break-glass hatch. Promote an existing account via the admin key:

    Fenêtre de terminal
    curl "$BASE_URL/api/v1/console/promote/console-admin?email=ops@bloonio.com" \
    -X POST -H "X-Admin-Key: YOUR_ADMIN_KEY"