Matrix logo

Router API

The public front door: validates a Supabase JWT, wakes the user's environment (Fly Machine or Railway service), and reverse-proxies to their daemon. Plus the internal admin and wake surfaces.

The router is the only public service (:443). It validates a Supabase JWT, ensures the user's environment is awake (Fly Machine or Railway service), and reverse-proxies the request to their daemon.

Public surface

MethodPathAuthPurpose
GET/healthznoneLiveness (also pings the database)
GET/v/versionnoneRouter version
ANY/*Supabase JWTWake-then-reverse-proxy to the user's daemon

All non-health traffic flows through the JWT middleware: the token identifies the user, the proxy looks up the user's environment, wakes it if needed (with a configurable WakeTimeout, default 30s), waits for daemon readiness (polling /healthz on the environment), then forwards the request.

Cody routing

Requests to /cody/* are routed to the co-located Cody engine (codyd) on its own port (default :8090). The /cody prefix is stripped before forwarding.

Environment lifecycle states

StateHTTP statusMeaning
active(proxied)Environment running, request forwarded
provisioning503Environment coming up; retry shortly
suspended451Account suspended
deleted410Account deleted

Internal surface

The internal mux is bound to a private address (ROUTER_INTERNAL_ADDR, not public):

MethodPathAuthPurpose
GET/healthznoneInternal liveness
POST/admin/usersAdmin tokenCreate-or-touch user + ensure environment + volume
GET/admin/users/{id}Admin tokenLookup user row (debug)
DELETE/admin/users/{id}Admin tokenDestroy environment + set state=deleted
POST/admin/users/{id}/suspendAdmin tokenSet state=suspended
POST/admin/users/{id}/restoreAdmin tokenSet state=active

Admin routes mount only when ROUTER_ADMIN_TOKEN is set. Both admin and wake routes use constant-time bearer comparison.

Create a user (admin)

POST /admin/users creates or touches a user and ensures an attached environment. The request blocks while the provider API provisions the volume and instance (synchronous in v1).

supabase_user_idstringrequired

The Supabase user UUID.

emailstring

User email (passed to the provisioner).

handlestring

Optional user handle.

regionstring

Override the default region for this environment.

curl -X POST http://router.internal/admin/users \
  -H "Authorization: Bearer $ROUTER_ADMIN_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"supabase_user_id": "uuid-here", "email": "user@example.com"}'

Auto-provisioning (first request)

When an authenticated user has no row in the database, the router can auto-provision their environment on the first request. This path is gated by an invite check: the user must have a redeemed invite. Concurrent first requests for the same user are deduplicated so only one environment is provisioned.

Provider support

The router supports two environment providers, selected by ROUTER_PROVIDER:

ProviderEnv varRequired credentials
Fly (default)flyFLY_API_TOKEN, FLY_APP_NAME, FLY_REGION
RailwayrailwayRAILWAY_API_TOKEN, RAILWAY_PROJECT_ID, RAILWAY_ENVIRONMENT_ID

Configuration

Env varDefaultPurpose
ROUTER_ADDR(required)Public listen address (e.g. :443)
ROUTER_INTERNAL_ADDR(required)Private admin listen address
SUPABASE_URL(required)Supabase project URL for JWKS
DATABASE_URL(required)Postgres connection string
ROUTER_ADMIN_TOKEN(empty)Admin bearer token; empty disables admin
ROUTER_DAEMON_PORT8080Port the daemon listens on per environment
ROUTER_CODY_PORT8090Port codyd listens on per environment
ROUTER_WAKE_TIMEOUT30sDeadline for environment wake
ROUTER_PROXY_TIMEOUT5mReverse-proxy timeout
ROUTER_PROBE_INTERVAL250msPoll cadence during daemon readiness wait
ROUTER_CORS_ORIGINS(allow-any)Comma-separated browser CORS allow-list
Deployment

How the router fits the per-user environment topology.