Skip to content

AI chat (user)

HTTP routes and behavior for ai chat (user).

POST /api/ai/chat # SSE-streamed conversation with tool use
GET /api/ai/available # effective availability + personal|shared|none source
GET /api/ai/settings # provider catalog, write-only credential flags, effective source
PUT /api/ai/settings # test + atomically save personal provider/model/key override
DELETE /api/ai/settings # clear personal override and return to granted included access
PUT /api/ai/credentials/{provider} # test + set/replace one personal API key (write-only)
DELETE /api/ai/credentials/{provider} # erase one personal API key
GET /api/ai/codex/status # personal linked state, safe account metadata, usage windows
POST /api/ai/codex/device/begin # begin ChatGPT device authorization
GET /api/ai/codex/device/{flowID} # poll this user's pending device flow
DELETE /api/ai/codex/device/{flowID} # cancel this user's pending device flow
DELETE /api/ai/codex # unlink this user's ChatGPT account
GET /api/ai/grok/status # personal xAI link state and safe account metadata
POST /api/ai/grok/device/begin # begin xAI Grok device authorization
GET /api/ai/grok/device/{flowID} # poll this user's pending xAI device flow
DELETE /api/ai/grok/device/{flowID} # cancel this user's pending xAI device flow
DELETE /api/ai/grok # unlink this user's xAI account

All personal settings, credentials, OAuth accounts, and device flows derive ownership from the authenticated caller; no user ID is accepted from the client. Both providers’ device/begin return a verification URL, one-time code, flow ID, expiry, and polling interval; the app opens the explicit ChatGPT or xAI browser sign-in while keeping access and refresh tokens off the device. Codex delegates its flow to the pinned app-server; the xAI flow is served directly against auth.x.ai with xAI’s public Grok CLI client, and its rotating refresh tokens are persisted per use. API keys and completed OAuth authorization are AES-256-GCM encrypted at rest, and responses expose configured booleans rather than secret values. A provider, model, key, or completed OAuth selection is accepted only after the exact candidate completes a small tool-free response turn; a failure leaves the previous key and selection unchanged.

Resolution is deterministic: a personal selection row is the explicit override; otherwise a user with an included-access grant receives the admin’s shared provider. If the personal key, OAuth link, runtime, or allowance is unavailable, that request fails as personal instead of silently switching accounts and spending shared quota. The source is resolved once per request and never changes during a provider turn. Chat admission is non-blocking and cost-aware: one active turn per user, 16 turns server-wide, and at most four included-provider turns; excess requests are rejected before any provider call.

View the maintained source for this page.