Server API Reference
The relay server exposes a REST-like HTTP API used by both the web UI and the CLI. Most endpoints require authentication via an API key (CLI) or session cookie (browser).
Authentication
Section titled “Authentication”API Key (CLI)
Section titled “API Key (CLI)”Pass your API key in the Authorization header:
Authorization: Bearer pk_live_abc123...Session Cookie (Browser)
Section titled “Session Cookie (Browser)”The web UI uses cookie-based sessions managed by better-auth. Log in via POST /api/auth/sign-in/email.
Health
Section titled “Health”GET /health
Section titled “GET /health”Returns server status. No authentication required.
GET /healthResponse:
{ "status": "ok" }Authentication Endpoints
Section titled “Authentication Endpoints”Authentication is handled by better-auth at the /api/auth/* prefix. See the better-auth documentation for the full list of endpoints.
POST /api/register
Section titled “POST /api/register”Register a new account or log in to an existing one and issue a CLI API key. Used by pizzapi setup.
Rate-limited: 5 requests per 15 minutes per IP.
Request body:
{ "name": "Jordan", // Required for new accounts; omit for existing "email": "you@example.com", "password": "••••••••"}Response:
{ "ok": true, "key": "pk_live_abc123..." }Runners
Section titled “Runners”GET /api/runners
Section titled “GET /api/runners”List all registered runner daemons.
Auth: Session cookie.
Response:
[ { "id": "runner_a1b2c3", "name": "my-macbook", "connected": true, "sessions": ["session_x1y2z3"] }]POST /api/runners/spawn
Section titled “POST /api/runners/spawn”Spawn a new agent session on a runner.
Auth: API key or session cookie.
Request body:
{ "runnerId": "runner_a1b2c3", "prompt": "Fix all TypeScript errors", "cwd": "/path/to/project", "model": "claude-opus-4-5"}Response:
{ "sessionId": "session_x1y2z3", "shareUrl": "https://relay.example.com/sessions/session_x1y2z3"}POST /api/runners/restart
Section titled “POST /api/runners/restart”Restart an agent session on a runner. Sends a restart signal to the runner daemon.
Auth: Session cookie.
Request body:
{ "runnerId": "runner_a1b2c3"}Response:
{ "ok": true }POST /api/runners/stop
Section titled “POST /api/runners/stop”Stop (shut down) a runner daemon.
Auth: Session cookie.
Request body:
{ "runnerId": "runner_a1b2c3"}Response:
{ "ok": true }POST /api/runners/terminal
Section titled “POST /api/runners/terminal”Register a new terminal (xterm) session on a runner.
Auth: Session cookie.
Request body:
{ "runnerId": "runner_a1b2c3", "cwd": "/path/to/project", // optional "cols": 80, // optional, default 80 "rows": 24 // optional, default 24}Response:
{ "ok": true, "terminalId": "uuid", "runnerId": "runner_a1b2c3" }GET /api/runners/{runnerId}/recent-folders
Section titled “GET /api/runners/{runnerId}/recent-folders”Get recently used working directories for a runner.
Auth: Session cookie.
Response:
{ "folders": ["/Users/jordan/Projects/app", "/Users/jordan/Projects/lib"]}DELETE /api/runners/{runnerId}/recent-folders
Section titled “DELETE /api/runners/{runnerId}/recent-folders”Remove a folder from the recent-folders list.
Auth: Session cookie.
Request body:
{ "path": "/Users/jordan/Projects/old-project" }Response:
{ "ok": true, "deleted": true }GET /api/runners/{runnerId}/models
Section titled “GET /api/runners/{runnerId}/models”List available AI models on a runner, excluding user-hidden models.
Auth: Session cookie.
Response:
{ "models": [ { "provider": "anthropic", "id": "claude-sonnet-4-20250514" }, { "provider": "openai", "id": "gpt-4o" } ]}GET /api/runners/{runnerId}/services
Section titled “GET /api/runners/{runnerId}/services”List registered services and UI panels for a runner.
Auth: Session cookie.
Response:
{ "serviceIds": ["git", "godmother"], "panels": [{ "id": "panel-1", "title": "Service Panel" }]}GET /api/runners/{runnerId}/skills
Section titled “GET /api/runners/{runnerId}/skills”List available skills on a runner (from Redis cache).
Auth: Session cookie.
Response:
{ "skills": ["deploy", "review-pr", "run-tests"]}GET /api/runners/{runnerId}/skills/{name}
Section titled “GET /api/runners/{runnerId}/skills/{name}”Get the full content of a specific skill.
Auth: Session cookie.
Response:
{ "name": "deploy", "content": "# Deploy Skill\n..." }POST /api/runners/{runnerId}/skills
Section titled “POST /api/runners/{runnerId}/skills”Create a new skill on the runner.
Auth: Session cookie.
Request body:
{ "name": "my-skill", "content": "# Skill instructions..." }Response:
{ "ok": true, "skills": ["my-skill", "deploy", "review-pr"] }POST /api/runners/{runnerId}/skills/refresh
Section titled “POST /api/runners/{runnerId}/skills/refresh”Ask the runner to re-scan skills from disk.
Auth: Session cookie.
Response:
{ "ok": true, "skills": ["deploy", "review-pr"] }PUT /api/runners/{runnerId}/skills/{name}
Section titled “PUT /api/runners/{runnerId}/skills/{name}”Update an existing skill.
Auth: Session cookie.
Request body:
{ "content": "# Updated skill content..." }Response:
{ "ok": true, "skills": ["deploy", "review-pr"] }DELETE /api/runners/{runnerId}/skills/{name}
Section titled “DELETE /api/runners/{runnerId}/skills/{name}”Delete a skill from the runner.
Auth: Session cookie.
Response:
{ "ok": true, "skills": ["deploy"] }POST /api/runners/{runnerId}/files
Section titled “POST /api/runners/{runnerId}/files”List files in a directory on the runner. Path must be within the runner’s allowed workspace roots.
Auth: Session cookie.
Request body:
{ "path": "/Users/jordan/Projects/app" }Response:
{ "ok": true, "files": [ { "name": "src", "type": "directory" }, { "name": "package.json", "type": "file" } ]}POST /api/runners/{runnerId}/search-files
Section titled “POST /api/runners/{runnerId}/search-files”Search for files by name within a directory on the runner.
Auth: Session cookie.
Request body:
{ "cwd": "/Users/jordan/Projects/app", "query": "component", "limit": 100 // optional, default 100}Response:
{ "ok": true, "files": ["src/components/Button.tsx", "src/components/Modal.tsx"]}POST /api/runners/{runnerId}/read-file
Section titled “POST /api/runners/{runnerId}/read-file”Read the contents of a file on the runner. Supports UTF-8 text and base64-encoded binary.
Auth: Session cookie.
Request body:
{ "path": "/Users/jordan/Projects/app/src/index.ts", "encoding": "utf8" // "utf8" (default, 512KB max) or "base64" (10MB max)}Response:
{ "ok": true, "content": "import express from 'express';\n..." }Git Operations
Section titled “Git Operations”Git operations (status, diff, branches, checkout, stage, unstage, commit, push) are handled entirely through the WebSocket service_message channel with serviceId="git", not via REST endpoints. See the WebSocket section below.
GET /api/runners/{runnerId}/sandbox-status
Section titled “GET /api/runners/{runnerId}/sandbox-status”Get the current sandbox configuration and status for a runner.
Auth: Session cookie.
Response:
{ "ok": true, "mode": "basic", "filesystem": { "denyRead": [], "allowWrite": ["/tmp"], "denyWrite": [] }, "network": { "allowedDomains": [], "deniedDomains": [] }}PUT /api/runners/{runnerId}/sandbox-config
Section titled “PUT /api/runners/{runnerId}/sandbox-config”Update the sandbox configuration for a runner.
Auth: Session cookie.
Request body:
{ "mode": "basic", // "none" | "basic" | "full" "filesystem": { "denyRead": [], "allowWrite": ["/tmp", "/Users/jordan/Projects"], "denyWrite": ["/etc"] }, "network": { "allowedDomains": ["api.github.com"], "deniedDomains": [] }}Response:
{ "ok": true }GET /api/runners/{runnerId}/usage
Section titled “GET /api/runners/{runnerId}/usage”Get token/cost usage statistics from the runner.
Auth: Session cookie.
Query params:
| Param | Type | Default | Description |
|---|---|---|---|
range | string | 90d | Time range: 7d, 30d, 90d, or all |
Response:
{ "ok": true, "totalInputTokens": 1234567, "totalOutputTokens": 456789, "totalCostUsd": 12.34, "sessions": []}GET /api/runners/{runnerId}/triggers
Section titled “GET /api/runners/{runnerId}/triggers”List trigger definitions and active listeners for a runner.
Auth: Session cookie.
Response:
{ "triggerDefs": [ { "type": "github_push", "description": "Fires on git push" } ], "listeners": [ { "triggerType": "github_push", "prompt": "Review the push", "cwd": "/project" } ]}GET /api/runners/{runnerId}/trigger-listeners
Section titled “GET /api/runners/{runnerId}/trigger-listeners”List active trigger listeners (auto-spawn subscriptions) for a runner.
Auth: Session cookie.
Response:
{ "listeners": [{ "listenerId": "listener_abc123", "triggerType": "github_push", "prompt": "...", "cwd": "..." }] }POST /api/runners/{runnerId}/trigger-listeners
Section titled “POST /api/runners/{runnerId}/trigger-listeners”Add a trigger listener that auto-spawns sessions when a trigger fires.
Auth: Session cookie.
Request body:
{ "triggerType": "github_push", "prompt": "Review the changes", // optional "cwd": "/path/to/project", // optional "model": { "provider": "anthropic", "id": "claude-sonnet-4-20250514" }, // optional "params": { "branch": "main" } // optional filter params}Response:
{ "ok": true, "listenerId": "listener_abc123", "triggerType": "github_push" }PUT /api/runners/{runnerId}/trigger-listeners/{target}
Section titled “PUT /api/runners/{runnerId}/trigger-listeners/{target}”Update an existing trigger listener’s configuration. Prefer passing a listenerId as {target} when multiple listeners share the same trigger type. Passing a trigger type is legacy behavior.
Auth: Session cookie.
Request body: Same fields as POST (all optional).
Response:
{ "ok": true, "listenerId": "listener_abc123", "triggerType": "github_push" }DELETE /api/runners/{runnerId}/trigger-listeners/{target}
Section titled “DELETE /api/runners/{runnerId}/trigger-listeners/{target}”Remove a trigger listener. Prefer passing a listenerId as {target} when deleting one specific listener. Passing a trigger type is legacy bulk-style behavior.
Auth: Session cookie.
Response:
{ "ok": true, "listenerId": "listener_abc123", "triggerType": "github_push", "removed": 1 }GET /api/runners/{runnerId}/agents
Section titled “GET /api/runners/{runnerId}/agents”List available agent definitions on a runner (from Redis cache).
Auth: Session cookie.
Response:
{ "agents": ["reviewer", "deployer"] }GET /api/runners/{runnerId}/agents/{name}
Section titled “GET /api/runners/{runnerId}/agents/{name}”Get the full content of a specific agent definition.
Auth: Session cookie.
Response:
{ "name": "reviewer", "content": "# Agent definition..." }POST /api/runners/{runnerId}/agents
Section titled “POST /api/runners/{runnerId}/agents”Create a new agent definition.
Auth: Session cookie.
Request body:
{ "name": "my-agent", "content": "# Agent instructions..." }Response:
{ "ok": true, "agents": ["my-agent", "reviewer"] }POST /api/runners/{runnerId}/agents/refresh
Section titled “POST /api/runners/{runnerId}/agents/refresh”Ask the runner to re-scan agent definitions from disk.
Auth: Session cookie.
Response:
{ "ok": true, "agents": ["reviewer", "deployer"] }PUT /api/runners/{runnerId}/agents/{name}
Section titled “PUT /api/runners/{runnerId}/agents/{name}”Update an existing agent definition.
Auth: Session cookie.
Request body:
{ "content": "# Updated agent content..." }Response:
{ "ok": true, "agents": ["reviewer", "deployer"] }DELETE /api/runners/{runnerId}/agents/{name}
Section titled “DELETE /api/runners/{runnerId}/agents/{name}”Delete an agent definition.
Auth: Session cookie.
Response:
{ "ok": true, "agents": ["deployer"] }GET /api/runners/{runnerId}/plugins
Section titled “GET /api/runners/{runnerId}/plugins”List Claude Code plugins available on the runner. Optionally pass ?cwd= to scan from a specific directory.
Auth: Session cookie.
Query params:
| Param | Type | Description |
|---|---|---|
cwd | string | Optional absolute path to scan for project-local plugins |
Response:
{ "plugins": [{ "name": "my-plugin", "path": "/path/to/plugin" }] }POST /api/runners/{runnerId}/plugins/refresh
Section titled “POST /api/runners/{runnerId}/plugins/refresh”Ask the runner to re-scan plugins from disk.
Auth: Session cookie.
Response:
{ "ok": true, "plugins": [] }Sessions
Section titled “Sessions”GET /api/sessions
Section titled “GET /api/sessions”List all sessions for the authenticated user, including both live (in-memory) and persisted sessions.
Auth: Session cookie.
Query params:
| Param | Type | Default | Description |
|---|---|---|---|
includePersisted | string | true | Set to false or 0 to exclude persisted (historical) sessions |
Response:
{ "sessions": [ { "sessionId": "session_x1y2z3", "runnerId": "runner_a1b2c3", "status": "running" } ], "persistedSessions": []}GET /api/sessions/pinned
Section titled “GET /api/sessions/pinned”List pinned sessions for the authenticated user.
Auth: Session cookie.
Response:
{ "pinnedSessions": [{ "sessionId": "session_x1y2z3", "isPinned": true }] }PUT /api/sessions/{sessionId}/pin
Section titled “PUT /api/sessions/{sessionId}/pin”Pin a session so it persists in the session list.
Auth: Session cookie.
Response:
{ "ok": true, "isPinned": true }DELETE /api/sessions/{sessionId}/pin
Section titled “DELETE /api/sessions/{sessionId}/pin”Unpin a session.
Auth: Session cookie.
Response:
{ "ok": true, "isPinned": false }POST /api/sessions/{sessionId}/attachments
Section titled “POST /api/sessions/{sessionId}/attachments”Upload file attachments to a session (e.g. for the agent to process). Accepts one or more files.
Auth: Session cookie.
Content-Type: multipart/form-data
Form fields: file or files (one or more File entries).
Max file size: Configured by the server (default: 10 MB).
Response:
{ "attachments": [ { "attachmentId": "att_uuid", "filename": "screenshot.png", "mimeType": "image/png", "size": 54321, "expiresAt": "2025-01-15T12:00:00Z" } ]}GET /api/attachments/{attachmentId}
Section titled “GET /api/attachments/{attachmentId}”Download a previously uploaded attachment. Returns the file with appropriate content headers.
Auth: Session cookie or API key (via x-api-key header or ?apiKey= query param).
Response: Binary file with headers:
Content-Type— the attachment’s MIME typeContent-Disposition—inline; filename="..."X-Attachment-Id— the attachment IDX-Attachment-Filename— percent-encoded original filename
Triggers
Section titled “Triggers”POST /api/sessions/{sessionId}/trigger
Section titled “POST /api/sessions/{sessionId}/trigger”Fire a trigger into a connected session. Used by external integrations to send events to running agents.
Auth: API key (x-api-key header) or session cookie.
Request body:
{ "type": "webhook", // trigger type identifier "payload": { "repo": "my/repo" }, // arbitrary payload object "deliverAs": "steer", // optional: "steer" (default, interrupts) or "followUp" (queues) "expectsResponse": false, // optional, default false "source": "github", // optional source identifier "summary": "New push to main" // optional human-readable summary}Response:
{ "ok": true, "triggerId": "ext_abc123" }GET /api/sessions/{sessionId}/triggers
Section titled “GET /api/sessions/{sessionId}/triggers”List recent trigger history for a session.
Auth: API key or session cookie.
Query params:
| Param | Type | Default | Description |
|---|---|---|---|
limit | number | 50 | Max triggers to return (capped at 200) |
Response:
{ "triggers": [ { "triggerId": "ext_abc123", "type": "webhook", "source": "external:github", "summary": "New push to main", "payload": {}, "deliverAs": "steer", "ts": "2025-01-15T12:00:00Z", "direction": "inbound" } ]}DELETE /api/sessions/{sessionId}/triggers
Section titled “DELETE /api/sessions/{sessionId}/triggers”Clear trigger history for a session.
Auth: API key or session cookie.
Response:
{ "ok": true }GET /api/sessions/{sessionId}/available-triggers
Section titled “GET /api/sessions/{sessionId}/available-triggers”List trigger types available on the session’s runner (from runner service catalog).
Auth: API key or session cookie.
Response:
{ "triggerDefs": [ { "type": "github_push", "description": "Fires on git push events", "params": [{ "name": "branch", "type": "string" }], "schema": {} } ]}GET /api/sessions/{sessionId}/trigger-subscriptions
Section titled “GET /api/sessions/{sessionId}/trigger-subscriptions”List active trigger subscriptions for a session.
Auth: API key or session cookie.
Response:
{ "subscriptions": [ { "subscriptionId": "sub_abc123", "triggerType": "github_push", "runnerId": "runner_a1b2c3" } ]}POST /api/sessions/{sessionId}/trigger-subscriptions
Section titled “POST /api/sessions/{sessionId}/trigger-subscriptions”Subscribe a session to a trigger type. The trigger type must be available on the session’s runner.
Auth: API key or session cookie.
Request body:
{ "triggerType": "github_push", "params": { "branch": "main" }, // optional, validated against trigger def "filters": [ // optional output filters { "field": "repo", "value": "my/repo", "op": "eq" } ], "filterMode": "and" // optional: "and" (default) or "or"}Response:
{ "ok": true, "subscriptionId": "sub_abc123", "triggerType": "github_push", "runnerId": "runner_a1b2c3"}PUT /api/sessions/{sessionId}/trigger-subscriptions/{target}
Section titled “PUT /api/sessions/{sessionId}/trigger-subscriptions/{target}”Update params/filters on an existing trigger subscription. Prefer passing a subscriptionId as {target} or via ?subscriptionId= when multiple same-type subscriptions exist. Passing only a trigger type is legacy behavior.
Auth: API key or session cookie.
Request body:
{ "params": { "branch": "develop" }, "filters": [{ "field": "author", "value": "bot", "op": "contains" }], "filterMode": "and"}Response:
{ "ok": true, "subscriptionId": "sub_abc123", "triggerType": "github_push", "runnerId": "runner_a1b2c3" }DELETE /api/sessions/{sessionId}/trigger-subscriptions/{target}
Section titled “DELETE /api/sessions/{sessionId}/trigger-subscriptions/{target}”Unsubscribe a session from a trigger subscription. Prefer passing a subscriptionId as {target} or via ?subscriptionId= when deleting one specific subscription. Passing only a trigger type is legacy bulk-style behavior.
Auth: API key or session cookie.
Response:
{ "ok": true, "subscriptionId": "sub_abc123", "triggerType": "github_push", "removed": 1 }POST /api/runners/{runnerId}/trigger-broadcast
Section titled “POST /api/runners/{runnerId}/trigger-broadcast”Broadcast a trigger to all sessions subscribed to a trigger type on this runner. Intended for runner services.
Auth: API key only (x-api-key header).
Request body:
{ "type": "github_push", "payload": { "repo": "my/repo", "branch": "main" }, "deliverAs": "steer", // optional: "steer" or "followUp" "source": "github", // optional "summary": "Push to main" // optional}Response:
{ "ok": true, "delivered": 3, // number of existing sessions that received the trigger "spawned": 1, // number of auto-spawned sessions from listeners "triggerId": "ext_abc123"}Webhooks
Section titled “Webhooks”Webhooks allow external services to spawn sessions and fire triggers via HMAC-authenticated HTTP requests.
POST /api/webhooks
Section titled “POST /api/webhooks”Create a new webhook.
Auth: Session cookie.
Request body:
{ "name": "Deploy on push", "source": "github", "runnerId": "runner_a1b2c3", // optional — runner to spawn sessions on "cwd": "/path/to/project", // optional "prompt": "Review the changes", // optional — initial prompt for spawned sessions "model": { "provider": "anthropic", "id": "claude-sonnet-4-20250514" }, // optional "eventFilter": ["push", "pull_request"] // optional — only fire for these event types}Response (201):
{ "webhook": { "id": "wh_uuid", "name": "Deploy on push", "source": "github", "secret": "whsec_...", "enabled": true, "runnerId": "runner_a1b2c3" }}GET /api/webhooks
Section titled “GET /api/webhooks”List all webhooks for the authenticated user.
Auth: Session cookie.
Response:
{ "webhooks": [{ "id": "wh_uuid", "name": "Deploy on push", "source": "github", "enabled": true }] }GET /api/webhooks/{id}
Section titled “GET /api/webhooks/{id}”Get details of a specific webhook.
Auth: Session cookie.
Response:
{ "webhook": { "id": "wh_uuid", "name": "...", "source": "...", "secret": "whsec_...", "enabled": true } }PUT /api/webhooks/{id}
Section titled “PUT /api/webhooks/{id}”Update a webhook’s configuration.
Auth: Session cookie.
Request body: Any subset of the creation fields (name, source, runnerId, cwd, prompt, model, eventFilter, enabled).
Response:
{ "webhook": { "id": "wh_uuid", "name": "Updated name", "enabled": true } }DELETE /api/webhooks/{id}
Section titled “DELETE /api/webhooks/{id}”Delete a webhook.
Auth: Session cookie.
Response:
{ "ok": true }POST /api/webhooks/{id}/fire
Section titled “POST /api/webhooks/{id}/fire”Fire a webhook — spawns a new session and delivers the payload as a trigger. No session cookie required — authenticated via HMAC signature.
Auth: HMAC-SHA256 signature of the raw request body using the webhook’s secret, sent in the X-Webhook-Signature header.
Request body: Any JSON object. If the body contains a type field, it’s checked against the webhook’s eventFilter.
Headers:
X-Webhook-Signature: <hex-encoded HMAC-SHA256>Content-Type: application/jsonResponse:
{ "ok": true, "triggerId": "wh_abc123", "sessionId": "session_x1y2z3" }If the event type is filtered out:
{ "ok": true, "filtered": true }Push Notifications
Section titled “Push Notifications”GET /api/push/vapid-public-key
Section titled “GET /api/push/vapid-public-key”Get the VAPID public key for Web Push subscription. No authentication required.
Response:
{ "publicKey": "BNx..." }POST /api/push/subscribe
Section titled “POST /api/push/subscribe”Subscribe the browser to push notifications.
Auth: Session cookie.
Request body:
{ "endpoint": "https://fcm.googleapis.com/fcm/send/...", "keys": { "p256dh": "base64-encoded-key", "auth": "base64-encoded-auth" }, "enabledEvents": "question,error" // optional comma-separated event list}Response:
{ "ok": true, "id": "sub_uuid" }POST /api/push/unsubscribe
Section titled “POST /api/push/unsubscribe”Unsubscribe the browser from push notifications.
Auth: Session cookie.
Request body:
{ "endpoint": "https://fcm.googleapis.com/fcm/send/..." }Response:
{ "ok": true }GET /api/push/subscriptions
Section titled “GET /api/push/subscriptions”List push subscriptions for the authenticated user.
Auth: Session cookie.
Response:
{ "subscriptions": [ { "id": "sub_uuid", "endpoint": "https://fcm.googleapis.com/...", "createdAt": "2025-01-15T12:00:00Z", "enabledEvents": "question,error", "suppressChildNotifications": false } ]}PUT /api/push/events
Section titled “PUT /api/push/events”Update which events trigger push notifications for a subscription.
Auth: Session cookie.
Request body:
{ "endpoint": "https://fcm.googleapis.com/...", "enabledEvents": "question,error,completion"}Response:
{ "ok": true }PUT /api/push/child-notifications
Section titled “PUT /api/push/child-notifications”Control whether child (sub-agent) sessions trigger push notifications.
Auth: Session cookie.
Request body:
{ "endpoint": "https://fcm.googleapis.com/...", "suppress": true}Response:
{ "ok": true }POST /api/push/answer
Section titled “POST /api/push/answer”Answer a pending agent question directly from a push notification (e.g. from mobile).
Auth: Session cookie.
Request body:
{ "sessionId": "session_x1y2z3", "toolCallId": "tc_abc123", "text": "Yes, proceed with the deployment"}Response:
{ "ok": true }Error codes:
409— No question pending, or answer already submitted403— Session not in collab mode502— Runner not connected
Settings
Section titled “Settings”GET /api/settings/hidden-models
Section titled “GET /api/settings/hidden-models”Get the list of hidden (disabled) models for the authenticated user.
Auth: Session cookie.
Response:
{ "hiddenModels": ["openai/gpt-4", "anthropic/claude-2"] }PUT /api/settings/hidden-models
Section titled “PUT /api/settings/hidden-models”Update the list of hidden models.
Auth: Session cookie.
Request body:
{ "hiddenModels": ["openai/gpt-4"] }Response:
{ "ok": true, "hiddenModels": ["openai/gpt-4"] }Tunnel (HTTP Proxy)
Section titled “Tunnel (HTTP Proxy)”The tunnel endpoints proxy HTTP requests to services running on the runner’s localhost. This allows the web UI to access dev servers, databases, or any local service through the relay.
* /api/tunnel/{sessionId}/{port}/*
Section titled “* /api/tunnel/{sessionId}/{port}/*”Session-based tunnel proxy. All HTTP methods are supported (GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS).
Auth: Session cookie (must be the session owner).
The request is forwarded to 127.0.0.1:{port} on the runner. HTML, JS, and CSS responses are rewritten to route absolute paths through the tunnel prefix. Auth headers (Cookie, Authorization, x-api-key) are stripped before forwarding.
* /api/tunnel/runner/{runnerId}/{port}/*
Section titled “* /api/tunnel/runner/{runnerId}/{port}/*”Runner-based tunnel proxy (preferred). Same as above but addressed by runner ID instead of session ID, making the URL stable across session restarts.
Auth: Session cookie (must own the runner).