REST API
The aeqi platform exposes a REST API for Company management, authentication,
billing, integrations, and the catch-all proxy that forwards /api/* into a
Company runtime. The canonical runtime selector is the X-Company header
(fallback X-Entity) and the company_id query parameter (legacy alias
trust_id). Some on-chain and protocol-level fields still carry the trust
term.
Use the REST API when software needs to operate aeqi over HTTP: account flows, Company launch, runtime provisioning, integrations, billing, public profiles, inference, and proxied runtime operations. Use MCP when an AI client should operate Company memory, quests, agents, events, and code intelligence as tools.
Base URL
| Environment | URL | Notes |
|---|---|---|
| Hosted | https://app.aeqi.ai/api |
Platform control plane. |
| Self-hosted | http://127.0.0.1:8443/api |
Default platform port. |
| Tenant runtime | http://127.0.0.1:8400+/api |
Per-Company runtime; reached through the platform proxy, not directly. |
/api/* routes are served by the platform binary (aeqi-platform.service). Anything not registered explicitly is forwarded through routes::proxy::catch_all_proxy_handler to the tenant runtime selected by the X-Company header (fallback X-Entity) or a company_id / trust_id query parameter.
Authentication
Most endpoints require a JWT bearer token. The token is obtained from one of several login flows (email + code, password, wallet/SIWE, passkey). The header is:
Authorization: Bearer <jwt>
The X-Company header selects which Company runtime a proxied call routes to
(the platform still accepts X-Entity as a fallback). Proxied runtime calls
return 400 { "error": "X-Company header required" } if no runtime is supplied.
Non-tenant platform routes such as login, billing, API keys, and /api/companies
do not need it.
A small number of endpoints use other auth modes:
- MCP key auth —
/api/mcpand/api/mcp/validaterequireAuthorization: Bearer sk_…;X-Api-Key: ak_…is optional but recommended so the platform can bind the call to the same user account. - Signed OAuth state —
/api/integrations/{provider}/callbackis reached by the user's browser after an OAuth provider redirect; the signedstatetoken authenticates the call. - Admin secret —
/api/admin/*requires the platform admin token, not a user JWT.
Full request/response details for the login flows live in Authentication.
Public Endpoints
No auth required.
Health
GET /api/health
GET /api/diagnostics/runtime-health
/api/health is the liveness check and returns { "status": "ok" }.
/api/diagnostics/runtime-health exposes the runtime health summary used by
operator and status surfaces.
Authentication entry points
GET /api/auth/mode
POST /api/auth/login
POST /api/auth/login/email
POST /api/auth/signup
POST /api/auth/verify
POST /api/auth/resend-code
Wallet auth (SIWE):
POST /api/auth/wallet/nonce
POST /api/auth/wallet/login
POST /api/auth/wallet/signup
Passkey auth:
POST /api/auth/passkey/register-begin
POST /api/auth/passkey/register-finish
POST /api/auth/passkey/login-begin
POST /api/auth/passkey/login-finish
Passwordless email sign-in (single login-codes row, three consume paths):
POST /api/auth/login/code/request
POST /api/auth/login/code/consume
POST /api/auth/login/magic/consume
TOTP login step:
POST /api/auth/totp/login
Password recovery:
POST /api/auth/forgot-password
POST /api/auth/reset-password
Invites and waitlist:
POST /api/auth/invite/check
POST /api/auth/waitlist
GET /api/auth/waitlist/confirm
Email unsubscribe:
GET /unsubscribe
POST /unsubscribe
The signed token in the unsubscribe URL is the credential for that endpoint.
Solana welcome flow
Mounted only when AEQI_SOLANA_RPC is configured. Used by the /welcome onboarding shell, which provisions a Solana custodial signer alongside the platform identity.
POST /api/auth/welcome/email-start
GET /api/auth/welcome/email-verify
POST /api/auth/welcome/email-verify-code
POST /api/auth/welcome/wallet-start
POST /api/auth/welcome/wallet-verify
POST /api/auth/welcome/passkey-register-start
POST /api/auth/welcome/passkey-register-finish
POST /api/auth/welcome/passkey-assert-start
POST /api/auth/welcome/passkey-assert-finish
GET /api/auth/welcome/google/start
GET /api/auth/welcome/google/callback
GET /api/auth/welcome/github/start
GET /api/auth/welcome/github/callback
OAuth provider callbacks
GET /api/integrations/google/callback
GET /api/integrations/github/callback
GET /api/integrations/etsy/callback
Reached by the user's browser after the OAuth provider redirects back. The signed state token resolves the owning agent + entity. The matching authenticated start/status endpoints are under Authenticated Endpoints → Integrations.
Webhooks
Inbound webhook handlers for external services:
POST /api/webhooks/stripe
POST /api/webhooks/deploy
POST /api/webhooks/telegram/{token}
POST /api/webhooks/whatsapp
Template catalog
GET /api/templates
GET /api/templates/default
GET /api/templates/{slug}
Public, no X-Company required. The catalog is platform-shared static content.
/api/templates is the company-launch catalog the /launch flow reads before
any Company runtime exists; it returns the two shipped company templates
(new-company, existing-company). /api/templates/default resolves to the
default launch template (new-company); /api/templates/{slug} returns one
template's full JSON. See Template schema.
Spawn (proxied)
POST /api/templates/spawn
POST /api/templates/spawn-into
Registered in the public router so they shadow /api/templates/{slug} (which would otherwise intercept the path and reject the POST); the catch-all proxy forwards them to the per-Company orchestrator selected by X-Company.
Economy + public profiles
GET /api/economy/list
GET /api/public/entities/{slug}
GET /api/public/company/{address}
GET /api/public/company/{address}/assets
GET /api/public/company/{address}/incorporation
GET /api/public/status/walks
/api/economy/list returns every Company whose placement has public=true, with on-chain address — drives /economy. /api/public/entities/{slug} returns the public profile JSON for a Company that has public=true; returns 404 for private workspaces (indistinguishable from non-existent). /api/public/company/{address} returns the public composite viewer payload (on-chain + IPFS + indexer) for an on-chain address when the linked workspace is public.
The /assets and /incorporation subresources expose public document bundles
for a public Company address when those modules are present.
/api/public/status/walks returns recent public walk status rows for the
landing status surface.
Public launch-site forms
POST /api/public/website/waitlist
POST /api/public/website/support-checkout
POST /api/public/slot/waitlist
Public, resolved from the Host header of the Company subdomain serving the
form. /api/public/website/waitlist joins the per-Company launch-site waitlist.
/api/public/website/support-checkout opens a day-one support purchase as a
destination charge via the Company's Express account.
/api/public/slot/waitlist is the anonymous "launching soon" placeholder
waitlist for a bare <slug> subdomain with no placement yet; it keys on the
slug rather than a Company.
Role invitations
GET /api/invitations/{token}
Resolves a role-invitation token to its details. Public so an unauth recipient can see what they're being invited to before accepting.
MCP
POST /api/mcp
POST /api/mcp/validate
POST /api/mcp accepts an MCP JSON-RPC request and returns its response.
/api/mcp/validate echoes back which actor and Company a key resolves to. Auth is
Authorization: Bearer sk_…; pass X-Api-Key: ak_… as well when binding the
call to a user account. GET and DELETE are not callable MCP transports on
the hosted platform today.
See MCP for the tool surface.
LLM proxy
ANY /api/llm/v1/{*path}
Forwards OpenAI-compatible chat traffic to the upstream LLM provider configured for the active Company. Use Inference (/v1/*) for end-user inference; this proxy is for internal runtime traffic.
Authenticated Endpoints
Require a valid JWT bearer. Proxied runtime endpoints additionally require a
Company runtime context via X-Company (fallback X-Entity) or the
company_id / trust_id query parameter.
Account
GET /api/auth/me
POST /api/auth/phishing-code
POST /api/auth/totp/setup
POST /api/auth/totp/verify
POST /api/auth/totp/disable
GET /api/auth/activity
GET /api/auth/sessions
POST /api/auth/sessions/revoke
POST /api/auth/sessions/revoke-others
GET /api/auth/invite-codes
POST /api/auth/invite-codes
GET /api/admin/overview
GET /api/admin/llm-provider
POST /api/admin/llm-provider
GET /api/account/notifications
POST /api/account/notifications/stop
POST /api/account/notifications/resume
/api/admin/overview is the user-facing admin view (returns 200 only if the caller is a platform admin); it is not part of the admin secret-guarded surface below.
/api/admin/llm-provider reads or updates the active hosted inference provider
configuration for platform admins.
The notification routes expose and update the user's channel suppression state.
Email change
POST /api/me/email/change/begin
POST /api/me/email/change/finish
Wallets
POST /api/me/wallets/link
PUT /api/me/wallets/{id}/primary
DELETE /api/me/wallets/{id}
Passkeys
POST /api/me/passkeys/add/begin
POST /api/me/passkeys/add/finish
POST /api/account/enroll-passkey
POST /api/wallet/upgrade-to-passkey
The last two return 501 Not Implemented until WS-4e ships.
Billing
POST /api/billing/checkout
GET /api/billing/subscription
POST /api/billing/portal
GET /api/billing/overview
POST /api/billing/credit-addon
POST /api/billing/top-up
POST /api/billing/plan-change/preview
POST /api/billing/plan-change/confirm
POST /api/billing/annual/confirm
POST /api/billing/plan-cancel
Subscription and payment management via Stripe. checkout opens a subscription
checkout; subscription and overview read current plan + balance state;
portal opens the Stripe customer portal. credit-addon and its alias
top-up purchase one-time credit. plan-change/preview returns the proration
preview for a plan switch and plan-change/confirm applies it; annual/confirm
confirms an annual upgrade. plan-cancel cancels the active subscription.
Companies
GET /api/companies
POST /api/companies
DELETE /api/companies/{company_id}
PUT /api/companies/{company_id}
GET /api/companies/{company_id}/assets
GET /api/companies/{company_id}/incorporation
GET /api/companies/{company_id}/email/messages
GET /api/companies/{company_id}/email/stats
POST /api/companies/{company_id}/email/test
GET /api/companies/{company_id}/website/analytics
GET /api/companies/{company_id}/payments
POST /api/companies/{company_id}/payouts/connect
POST /api/companies/{company_id}/runtime/restart
/api/companies is the user-owned Company collection. It is registered
platform-side (before the catch-all proxy) so it returns the caller's
cross-runtime list rather than whatever single runtime the scoped Company
header currently points at. POST creates a Company, GET lists; the
{company_id} routes update or delete one.
The assets, incorporation, email, and website/analytics subroutes back
the Company document, incorporation, inbox, and analytics panels for a selected
runtime (email/stats returns inbox counters for the panel header). payments lists the Company's payment records;
payouts/connect opens Stripe Express onboarding so the Company can receive
payouts. runtime/restart reboots the Company's VPS in place (data and IP
preserved; owner-only, same auth as the Company DELETE).
/start launch
POST /api/start/launch
POST /api/start/check-name
POST /api/start/suggest-idea
POST /api/start/suggest-name
GET /api/start/launch/status/{trust_id}
GET /api/start/launch/stream/{trust_id}
GET /api/start/share/{trust_id}
POST /api/start/share/{trust_id}/verify
GET /api/start/share/{trust_id}/weekly
POST /api/start/share/{trust_id}/weekly/verify
launch provisions a personal Company via the /start experience. Gated by subscription status (subscription_required HTTP 402 if missing) and a workspace cap of 10 companies per user (workspace_cap_exceeded HTTP 402; admins exempt).
launch/status/{trust_id} polls provisioning progress for a launched Company;
launch/stream/{trust_id} is the SSE variant streaming the same progress live.
suggest-idea and suggest-name back the /start flow's LLM suggestions for
a company idea and an available display name.
share/{trust_id} returns the launch-announcement share code and prefilled
post; share/{trust_id}/verify runs platform-side post verification and awards
a one-time flat credit bonus (the platform checks the post, never the tenant
runtime). The weekly pair is the weekly progress-post share loop: same
platform-side post verification, but the reward is a bounded top-up of the
monthly operating-credit grant, claimable once per ISO week.
Request:
{
"template": "default",
"display_name": "My Company",
"mission": "optional one-line mission statement",
"plan": "growth"
}
name is accepted as a fallback alias for display_name. If template is omitted, the configured default blueprint is used.
Response (200):
{
"ok": true,
"trust_id": "company-id",
"display_name": "My Company",
"website_domain": "my-company.aeqi.ai",
"website_url": "https://my-company.aeqi.ai",
"email_address": null
}
The trust_id field carries the new Company's id. Placement provisioning (sandbox / host / VPS) proceeds async; poll GET /api/start/launch/status/{trust_id} until its status flips from pending to ready. check-name returns whether a display name is available for the caller.
Runtime provisioning
POST /api/runtime/provision
POST /api/runtime/provision-treasury
GET /api/runtime/status
Provision attaches managed runtime capacity to a Company. The Stripe and treasury
paths converge on the same placement lifecycle; status reads the live
placement and service state.
Solana and protocol routes
Mounted only when the relevant Solana services are configured.
POST /api/companies/create
POST /api/solana/companies/create
POST /api/solana/first-buy
POST /api/solana/curve-sell
POST /api/solana/token-mint
POST /api/solana/token-burn
POST /api/solana/token-transfer
POST /api/solana/vesting-create
POST /api/solana/budget-module-init
POST /api/solana/budget-create
POST /api/solana/funding-module-init
POST /api/solana/funding-request-create
GET /api/curves/{trust_id}/state
These authenticated routes back staged protocol modules: genesis, first-buy,
curves, token operations, vesting, budgets, and funding requests. Treat them as
deployment-dependent protocol surfaces, not baseline hosted-app requirements.
Normal hosted users create Companies through /api/companies or
/api/start/launch; protocol genesis is for Solana-enabled deployments.
Architect deploy
POST /api/architect/deploy
Same provisioning path as /start/launch, but the Blueprint is the architect-generated inline JSON rather than a static catalog slug. Earlier verbs (architect.draft, architect.refine) live on the runtime and are reached via the proxy.
Integrations
Company app OAuth and per-agent OAuth.
Company-scoped app connections:
GET /api/trust/{trust_ref}/apps/google/start
GET /api/trust/{trust_ref}/apps/google/status
GET /api/trust/{trust_ref}/apps/etsy/start
GET /api/trust/{trust_ref}/apps/etsy/status
Telegram gateway for a Company (the trust_ref path segment is the
lower-level runtime selector behind the Company):
POST /api/trust/{trust_ref}/apps/telegram/link-code
GET /api/trust/{trust_ref}/apps/telegram/status
GET /api/trust/{trust_ref}/apps/telegram/bindings
DELETE /api/trust/{trust_ref}/apps/telegram/bindings/{binding_id}
link-code mints a /start link code that binds a Telegram chat to the
Company's CEO via the shared central bot; status reports the gateway state.
bindings lists the Telegram accounts connected to this Company, and the
{binding_id} route revokes one. Both are scoped so a Company only ever sees
and revokes its own bindings.
Per-agent OAuth, one start/status pair per provider:
GET /api/agents/{agent_id}/integrations/google/start
GET /api/agents/{agent_id}/integrations/google/status
GET /api/agents/{agent_id}/integrations/github/start
GET /api/agents/{agent_id}/integrations/github/status
start returns a signed redirect to the provider. The matching callbacks
/api/integrations/google/callback, /api/integrations/github/callback, and
/api/integrations/etsy/callback are listed above as public routes; providers
redirect there without our auth header.
API keys
POST /api/keys
GET /api/keys
DELETE /api/keys/{id}
POST /api/account/api-key
/api/account/api-key mints a single personal API key (older surface). /api/keys is the labelled, multi-key collection.
Hosting
GET /api/hosting/domains
POST /api/hosting/domains
DELETE /api/hosting/domains/{domain}
GET /api/hosting/waitlist
POST /api/hosting/deploy
Manage custom domains for Company runtimes. /api/hosting/waitlist lists the
launch-site waitlist signups for a Company the caller owns (the public join
form is POST /api/public/website/waitlist). /api/hosting/deploy is the
entrypoint for the runtime apps.deploy tool: it builds the Company's seeded
site and flips the Company domain from the launch page to the built site
(owner-authenticated).
Role invitations
POST /api/companies/{company_id}/roles/{role_id}/invitations
GET /api/companies/{company_id}/invitations
POST /api/invitations/{token}/accept
POST /api/invitations/{token}/decline
GET /api/me/directed-entities
Invite users to roles within a Company; accept or decline. Creating an
invitation is scoped to a {company_id} and {role_id}; the token-based
accept/decline routes pair with the public GET /api/invitations/{token}
resolver. /api/me/directed-entities lists every Company the caller has been
granted directed access to.
Identity resolver
GET /api/identity/resolve
Authenticated batch lookup for public keys into known identity records. The batch size is capped by the platform resolver.
Proxied Runtime Endpoints
Everything under /api/* that is not explicitly listed above is forwarded by
catch_all_proxy_handler to the runtime selected by X-Company (fallback
X-Entity) or the company_id / trust_id query parameter. Examples handled
this way:
GET /api/agents
POST /api/agents/spawn
GET /api/quests
POST /api/quests
GET /api/ideas
POST /api/ideas
GET /api/sessions
POST /api/chat
A few proxied paths have platform-side specialisation registered explicitly so the response can be patched before being returned:
GET /api/ws— WebSocket proxy.GET /api/chat/stream— server-sent events / WebSocket stream proxy.GET /api/ideas/{id}/comments— proxies the runtime reply but injects user display names from the platform user table.GET /api/roles,GET /api/roles/{id}— proxies and patchesoccupant_namefor human occupants.
Runtime ideas surface
The runtime registers the following routes under /api/ideas/*. Use them
through the platform proxy with X-Company set, not directly against the
per-tenant runtime port.
GET /api/ideas List visible ideas (query: agent_id?)
POST /api/ideas Create or supersede an idea
POST /api/ideas/files Upload a root file-backed Idea
GET /api/ideas/search Hybrid BM25 + vector search
GET /api/ideas/prefix Prefix-match for autocomplete
POST /api/ideas/by-ids Batch fetch by id list
GET /api/ideas/profile Profile-scoped catalog read
GET /api/ideas/graph Adjacency view for the graph renderer
POST /api/ideas/seed Bulk insert seed ideas (blueprint apply)
PUT /api/ideas/{id} Update name / content / tags
DELETE /api/ideas/{id} Delete (fails 409 if a quest still references it)
POST /api/ideas/{id}/files Upload a file-backed child Idea
GET /api/ideas/{id}/edges Edges incident to one idea
POST /api/ideas/{id}/edges Add a typed edge
DELETE /api/ideas/{id}/edges Remove a typed edge
GET /api/ideas/{id}/activity Activity feed (system events on this idea)
GET /api/ideas/{id}/comments Comment thread (specialised at the platform)
POST /api/ideas/{id}/subscribe Subscribe the caller to comment notifications
GET /api/ideas/{id}/children List children (Tables Phase 2)
PUT /api/ideas/{id}/properties Update typed properties bag
File uploads use multipart/form-data. The required fields are agent_id and
file; optional fields are scope and, for root uploads, the parentless route
/api/ideas/files. The child route sets parent_idea_id from the path and
forwards both forms to the runtime files_upload IPC verb, which creates an
Idea wrapper for the artifact.
link, feedback, and walk are MCP-only verbs — there are no REST routes for them. The MCP dispatcher rewrites them into IPC commands (link_idea, feedback_idea, walk_ideas).
Admin Endpoints
Require the platform admin secret (header), not a user JWT.
GET /api/admin/containers
POST /api/admin/containers/{id}/restart
GET /api/admin/roots
POST /api/admin/roots/{name}/promote-host
POST /api/admin/roots/{name}/seed
POST /api/admin/update
GET /api/admin/stats
GET /api/admin/template-packs
POST /api/admin/template-packs
GET /api/admin/template-packs/{slug}
POST /api/admin/template-packs/{slug}/templates
POST /api/admin/vps/spawn-test
Response Format
Responses are not wrapped in a uniform envelope — different handlers return different shapes. Common patterns:
{ "ok": true, "id": "..." }
{ "items": [ ... ], "next_cursor": null }
Errors return a 4xx or 5xx status with a body of one of:
{ "ok": false, "error": "code", "message": "human-readable description" }
{ "error": "code", "message": "..." }
Inference and MCP have their own error shapes — see those references.
Rate Limiting
Platform-side: no per-endpoint quotas are published. The tenant runtime applies tower_governor with SmartIpKeyExtractor — abuse can trigger 429 responses. The runtime-bound proxy always injects X-Forwarded-For: 127.0.0.1 from inside the platform binary so internal calls survive the key extractor.
Next Steps
- Authentication — JWT lifecycle, signup, login flows.
- Inference —
/v1/*OpenAI-compatible chat. - MCP — operate the same surface programmatically.
- Concepts — the four primitives.