Skip to content

HTTP Server

Start a local HTTP bridge when the caller isn't a Node.js process, or when you want a process boundary between the SDK and the caller.

Starting the Server

ts
import { startSwitchboardServer } from "switchboard-ai-sdk";

const server = await startSwitchboardServer({
  port: 3000
});

console.log(server.url); // http://127.0.0.1:3000

You can also create the server without starting it immediately:

ts
import { createSwitchboardServer } from "switchboard-ai-sdk";

const server = createSwitchboardServer({ port: 3000 });
// Configure, add middleware, etc.
server.listen(3000, "127.0.0.1");

Endpoints

MethodPathDescription
GET/configRead current process-level provider config
PUT/configReplace process-level provider config
GET/healthAggregate health and auth status of all tools
GET/health/:toolIdHealth status of a specific tool
GET/discoverDiscover available AI tools
POST/auth/:toolIdStart authentication for a provider
POST/chatRoute a chat request across preferred providers
POST/chat/:toolIdSend a chat prompt to a provider

GET /config

Returns the current process-level configuration.

bash
curl http://127.0.0.1:3000/config
json
{
  "config": {
    "codexModel": "gpt-5.5",
    "codexSandbox": "workspace-write"
  }
}

PUT /config

Replace the current configuration. The request body becomes the new process-level config; unspecified fields are removed.

bash
curl -X PUT http://127.0.0.1:3000/config \
  -H "content-type: application/json" \
  -d '{
    "codexModel": "gpt-5.5",
    "codexSandbox": "workspace-write"
  }'
json
{
  "config": {
    "codexModel": "gpt-5.5",
    "codexSandbox": "workspace-write"
  }
}

GET /discover

bash
curl http://127.0.0.1:3000/discover
json
{
  "tools": [
    {
      "id": "codex",
      "name": "Codex",
      "type": "agent",
      "available": true,
      "version": "1.2.3",
      "capabilities": ["agent-task", "code-analysis", "code-edit", "chat", "health-check"],
      "models": ["gpt-5-codex"],
      "defaultModel": "gpt-5-codex"
    },
    {
      "id": "ollama",
      "name": "Ollama",
      "type": "runtime",
      "available": true,
      "version": "0.8.0",
      "capabilities": ["chat", "completion", "model-list", "health-check"],
      "models": ["qwen3:14b"],
      "defaultModel": "qwen3:14b"
    }
  ]
}

GET /health

Returns aggregate health status of all tools, including auth state and normalized provider usage-limit windows when a provider exposes them locally.

bash
curl http://127.0.0.1:3000/health
json
{
  "status": "ok",
  "version": "0.1.8",
  "uptimeMs": 918,
  "tools": [
    {
      "toolId": "codex",
      "status": "unavailable",
      "available": false,
      "authSupported": true,
      "authenticated": false,
      "authStatus": "unauthenticated",
      "usageLimits": {
        "status": "available",
        "source": "local_session",
        "plan": "plus",
        "windows": {
          "five_hour": {
            "usedPercentage": 36,
            "remainingPercentage": 64,
            "resetsAt": "2026-06-07T12:45:46.000Z"
          },
          "seven_day": {
            "usedPercentage": 43,
            "remainingPercentage": 57,
            "resetsAt": "2026-06-11T17:49:07.000Z"
          }
        }
      },
      "reason": "Codex requires authentication before it can handle requests.",
      "latencyMs": 55,
      "checkedAt": "2026-06-17T12:54:44.900Z"
    }
  ]
}

GET /health/:toolId

Returns the same normalized auth and usage-limit fields for one tool.

bash
curl http://127.0.0.1:3000/health/codex
json
{
  "toolId": "codex",
  "status": "healthy",
  "available": true,
  "authSupported": true,
  "authenticated": true,
  "authStatus": "authenticated",
  "usageLimits": {
    "status": "available",
    "source": "local_session",
    "plan": "plus",
    "windows": {
      "five_hour": {
        "usedPercentage": 36,
        "remainingPercentage": 64,
        "resetsAt": "2026-06-07T12:45:46.000Z"
      },
      "seven_day": {
        "usedPercentage": 43,
        "remainingPercentage": 57,
        "resetsAt": "2026-06-11T17:49:07.000Z"
      }
    }
  },
  "version": "codex-cli 0.136.0",
  "latencyMs": 406,
  "checkedAt": "2026-06-17T12:54:44.900Z"
}

POST /auth/:toolId

bash
curl -X POST http://127.0.0.1:3000/auth/codex
json
{
  "toolId": "codex",
  "status": "started",
  "authenticated": false,
  "command": "codex login",
  "instructions": "Visit https://example.com/device and enter the code shown by Codex.",
  "output": "Visit https://example.com/device and enter the code shown by Codex.",
  "checkedAt": "2026-06-17T12:54:44.900Z"
}

POST /chat/:toolId

Request:

bash
curl -X POST http://127.0.0.1:3000/chat/codex \
  -H "content-type: application/json" \
  -d '{
    "messages": [
      { "role": "user", "content": "Reply with a short list of 5 ideas." }
    ],
    "timeoutMs": 30000
  }'

Response:

json
{
  "toolId": "codex",
  "type": "agent",
  "model": "gpt-5.4",
  "result": {
    "message": {
      "role": "assistant",
      "content": "1. Add a lightweight onboarding flow..."
    },
    "usage": {
      "input_tokens": 16646,
      "cached_input_tokens": 2432,
      "output_tokens": 76,
      "reasoning_output_tokens": 11
    }
  },
  "latencyMs": 8086
}

POST /chat

Use this route when you want the server to retry and fall back across providers in the order you specify.

bash
curl -X POST http://127.0.0.1:3000/chat \
  -H "content-type: application/json" \
  -d '{
    "providers": ["codex", "claude-code", "opencode", "ollama"],
    "messages": [
      { "role": "user", "content": "Reply with a short list of 5 ideas." }
    ],
    "retries": 1,
    "perAttemptTimeoutMs": 15000
  }'
json
{
  "toolId": "ollama",
  "fallbackUsed": true,
  "attempts": [
    {
      "toolId": "codex",
      "tryIndex": 0,
      "stage": "execution",
      "outcome": "failed",
      "reason": "timeout"
    },
    {
      "toolId": "ollama",
      "tryIndex": 0,
      "stage": "execution",
      "outcome": "succeeded"
    }
  ]
}

HTTP Error Responses

All errors use a consistent envelope:

json
{
  "error": {
    "code": "tool_not_found",
    "message": "Tool 'unknown' is not supported."
  }
}

Error codes map to HTTP status codes:

HTTP StatusError CodeMeaning
400invalid_requestMalformed request body or invalid config
401tool_auth_requiredProvider requires authentication
404tool_not_foundUnknown tool ID
502provider_execution_failedProvider accepted the request but failed to produce a response
503tool_unavailableProvider is installed but not currently reachable
504timeoutOperation exceeded timeout
500internal_errorUnexpected server error

Server vs Direct SDK

Use the direct SDK when:

  • Your app runs in Node.js or Electron
  • You want typed exceptions instead of HTTP error codes
  • You want in-process objects with zero serialization overhead

Use the HTTP server when:

  • Your caller is not a Node.js process
  • You need a process or network boundary
  • JSON error payloads are a better fit for your caller

Released under the MIT License. · llms.txt