Portal contract (auth, cookies, APIs)
Guided onboarding & connection check
Walks signup (when enabled) → POST /portal/session → project key → eligible model → wallet or BYOK funding snapshot → one capped POST /v1/chat/completions. Progress follows server state from GET /portal/session, GET /v1/keys, GET /v1/marketplace/models, and either GET /v1/wallet/balance or GET /v1/byok/credentials. Copyable OpenAI-compatible SDK snippets use only https://api.cybertronic.dev and the minted project key shown once in-page. Secrets are never written to web storage. Completion requires a verified gateway response (non-empty assistant content), not merely submitting a form.
- 1. Public signup (optional)Click Create starter project only when you intend to POST /v1/signup; this page never probes signup on load.
- 2. Portal sessionSign in or create a session cookie.
- 3. Project credentialList or mint a scoped project key.
- 4. Eligible modelPick an executable marketplace model.
- 5. Funding snapshotWallet balance from GET /v1/wallet/balance.
- 6. Capped production chatRun one low max_tokens gateway test.
OpenAI-compatible SDK config (copyable)
Python (openai)
curl
JavaScript (openai)
Sign in
When DAROUTER_PORTAL_DEMO_LOGIN=true on this gateway, username demo / password demo mints a starter session. Otherwise use a tenant API key. The demo password is never a production default.
Single sign-on
Continue starts GET /v1/sso/oidc/authorize?organization_id=…, the existing OIDC entrypoint. An operator must already have registered an OIDC provider for that organization out of band; otherwise the identity provider redirect returns a JSON error instead of a login page. This page cannot register a new identity provider and does not invent one.
SAML deployments: your identity provider fetches SP metadata from GET /v1/sso/saml/metadata?organization_id=… and posts the assertion to POST /v1/sso/saml/acs?organization_id=…. Both are service-provider-initiated endpoints already documented for admins; this page only links the metadata document, it does not start an IdP-initiated login.
Session status
From GET /portal/session and GET /portal/sessions. Reports what the session cookie proves and lists process-local portal sessions for your identity (id, created_at, expires_at, auth_method, optional current). Revoke other bindings with DELETE /portal/sessions/{id}. Credential mutations call POST /portal/session/reauth first to rotate the cookie token. Cookie tokens and API keys are never listed.
- Session
- Not signed in.
Emergency revoke-all (compromise response)
Use POST /portal/security/revoke-all to sign out every portal session for your identity and optionally revoke or rotate listed project keys and service accounts. Requires typing REVOKE ALL, a recent re-authentication, and credentials.write when revoking credentials. You will be signed out everywhere when sessions are revoked.
Organization & role
From GET /portal/session (organization_id, project_id, role), GET /v1/rbac/permissions (effective permissions), GET /v1/organizations/projects (same-organization projects), and POST /portal/session/switch (server-authorized project rebind). Values come only from the session cookie, never from the URL. Member invite/list/update/remove are leftover (no member-roster API).
- Organization
- Sign in to load context.
Service accounts
From GET /v1/service-accounts, POST /v1/service-accounts, POST /v1/service-accounts/{id}/rotate, POST /v1/service-accounts/{id}/disable, POST /v1/service-accounts/{id}/enable, and POST /v1/service-accounts/{id}/retire using the session cookie, scoped to the current project. Minted keys are shown once and never written to web storage. Mutations require credentials.write.
Eligible models
From GET /v1/marketplace/models using the session cookie (cursor pagination via after / next_after). Detail and changelog use GET /v1/marketplace/models/{id} and GET /v1/marketplace/models/{id}/changelog. Prices and units come from the API only; rows without pricing show no invented rates. HTTP 200 is not quality.
Offer detail & changelog
—
—
Compare offers
Side-by-side fields from loaded marketplace JSON only (no invented pricing).
Usage & spend
After sign-in, this panel reads GET /v1/budgets and GET /v1/budgets/{id}/usage for governance budget pools, GET /v1/operations/usage (optional from/to window), GET /v1/wallet/balance, GET /v1/wallet/transactions, GET /v1/billing/invoices, and GET /v1/billing/commercial-utilization (RFC3339 window derived from the date inputs) with the session cookie. Durable billed totals come from provider_billable_events. Budget remaining, hard limit, and consumed are labeled separately from prepaid wallet and invoice totals. Commercial utilization shows negotiated upstream estimates with charge_path=listed_marketplace (display-only negotiated rates; customer charges stay on listed marketplace prices). Bounded JSON/CSV export bundles the same snapshot (max 200 transaction rows). Each value is taken exactly from the API JSON fields. Tax, savings, and funded balances are never invented.
- Darouter-billed rated micros
- Sign in to load usage.
Budget alerts
After sign-in, this panel reads GET /v1/notifications/budget-alerts with the session cookie. Each row shows kind, threshold_percent, fired_at, budget_pool_id, and period_start from the API JSON only. This is a durable threshold-firing inbox — not email, webhooks, or funded-balance delivery. Threshold create/update/disable is not available on tenant APIs.
Prepaid wallet
From GET /v1/wallet/balance. Each admin grant is a cash lot. POST /v1/billing/checkout starts a Stripe-hosted session; a later signed webhook grants the lot. Chat holds then captures oldest-funded lots first. Empty funded wallets return HTTP 402 with an OpenAI-shaped insufficient_quota error. Auto-reload is a stored preference: when enabled and the balance is at or below the threshold, a 402 includes a Checkout URL. This is not a saved card, Stripe Customer, tax, cash-out, or a promo credit.
- auto_reload
- Sign in to load balance.
—
Receipts
From GET /v1/wallet/transactions. Grants, captures, and refunds. Holds are omitted. Not a tax invoice.
—
Rated attempts
From GET /v1/billing/events. Immutable per-attempt rating beside the charge. Not a tax invoice.
—
BYOK credentials
From GET /v1/byok/credentials, POST /v1/byok/credentials, POST /v1/byok/credentials/{id}/rotate, and POST /v1/byok/credentials/{id}/revoke. Lists non-secret metadata only (credential_version, rotated_at from the API). Provider secrets are write-only: cleared from inputs on submit and never written to web storage. If the API returns a secret field it is shown once in this page only. Mutations need credentials.write. Provider accounts and eligibility wiring are leftover.
Project keys
From GET /v1/keys, POST /v1/keys, POST /v1/keys/{key_id}/revoke, and POST /v1/keys/{key_id}/rotate. The project is taken from the session. The secret is shown once after create or rotate and is never written to storage. Mutations need credentials.write.
Key audit
From GET /v1/audit/events. Tenant-scoped create/revoke records only. Raw keys and request bodies are never stored. Not a SIEM export.
—
Virtual model policy composer
Preview and export a VirtualModelPolicy document that ParsePolicyDocument accepts. Only the fields on this form are emitted; unsupported controls are omitted (never silently active). Org allow/deny governance policies use a different shape and are out of scope here.
Targets
Each target needs provider and model. Optional account and priority are included only when set.
—
Draft, diff, activate & rollback
After sign-in, lists org-visible virtual models from GET /v1/virtual-models and version metadata from GET /v1/virtual-models/{id}. Saving a draft posts the composer export to POST /v1/virtual-models/{id}/versions (no second policy store). Activate and rollback call POST …/activate and POST …/rollback with expected_active_version_id compare-and-swap. Success labels require a server 200 response; HTTP 409 stale CAS and HTTP 403 RBAC denials are shown honestly. Mutations require credentials.write.
Policy diff (deterministic target comparison vs active version before activate):
—
Routing & optimization
Looks up one tenant-owned optimizer decision via GET /v1/optimizer/decisions/{decision_id} with the session cookie. Shows policy/arm identity, every launched attempt (execution mode, won, status, per-attempt cost), and outcome presence (missing or reported only). HTTP 200 is not task success; quality is never invented. WinnerCostMicros sums costs for won attempts only — do not sum every attempt as customer-billed. After a chat send, X-Darouter-Decision-ID and X-Darouter-Route-Explanation are captured when present.
Last route explanation (from chat response headers; not quality):
—
- Decision
- Paste a decision ID or send a chat message.
Efficiency advisor
Advisory only: GET /v1/optimizer/efficiency-advisor and opt-in via POST /v1/optimizer/efficiency-advisor/apply. HTTP 200 is not task success; transforms apply only after application outcomes and quality gates.
- Advisor
- Sign in and load advisor.
Chat playground
Sends POST /v1/chat/completions with the session cookie. Streaming and tools stay off unless the selected offer lists those capabilities. Send uses the same gateway path as an OpenAI SDK client, including budgets and governance.
Request trace
Paste X-Request-ID or X-Darouter-Decision-ID from a playground response header, then look up the tenant trace. Metadata only — no bodies or provider secrets.
—