Settings API
Settings control every aspect of Stagent’s behavior — from API key management and budget limits to model routing and runtime tuning. Each configuration domain lives under its own sub-route, so clients only fetch and update what they need.
Quick Start
Check provider status, configure an API key, and set a budget limit — a typical setup flow:
// 1. Get the current provider overview
const res1: Response = await fetch('/api/settings/providers');
const { providers, routingPreference }: { providers: Record<string, any>; routingPreference: string } = await res1.json();
console.log(`Anthropic configured: ${providers.anthropic.configured}`);
console.log(`Routing: ${routingPreference}`);
// 2. Set an Anthropic API key
await fetch('/api/settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ apiKey: 'sk-ant-api03-...' }),
});
// 3. Set a daily and monthly budget limit
await fetch('/api/settings/budgets', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ dailyLimit: 10.00, monthlyLimit: 200.00 }),
});
// 4. Route to the cheapest available model
await fetch('/api/settings/routing', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ preference: 'cost' }),
});
// 5. Test the connection
const testRes: Response = await fetch('/api/settings/test', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ runtime: 'claude-code' }),
});
const test: { connected: boolean } = await testRes.json();
console.log(`Connected: ${test.connected}`); Base URL
/api/settings
Provider Configuration
Get Provider Overview
/api/settings/providers Aggregated provider status including configured runtimes, auth methods, dual-billing detection, and routing preference.
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| providers.anthropic.configured | boolean | * | Whether any Anthropic runtime is configured |
| providers.anthropic.authMethod | string | * | Current auth method (oauth, api-key, etc.) |
| providers.anthropic.hasKey | boolean | * | Whether an API key is present |
| providers.anthropic.dualBilling | boolean | * | True when both OAuth and API key are active |
| providers.anthropic.runtimes | object[] | * | Runtime setup states for Claude Code and Anthropic Direct |
| providers.openai.configured | boolean | * | Whether any OpenAI runtime is configured |
| providers.openai.hasKey | boolean | * | Whether an OpenAI API key is present |
| providers.openai.runtimes | object[] | * | Runtime setup states for Codex and OpenAI Direct |
| routingPreference | enum | * | cost, latency, quality, or manual |
| configuredProviderCount | number | * | Number of providers with at least one runtime configured |
Check which providers are ready before assigning tasks to agents:
// Check provider readiness before creating tasks
const res: Response = await fetch('http://localhost:3000/api/settings/providers');
const { providers, routingPreference, configuredProviderCount }: {
providers: Record<string, any>;
routingPreference: string;
configuredProviderCount: number;
} = await res.json();
console.log(`${configuredProviderCount} provider(s) configured`);
console.log(`Anthropic: ${providers.anthropic.configured ? 'ready' : 'not configured'}`);
console.log(`OpenAI: ${providers.openai.configured ? 'ready' : 'not configured'}`);
console.log(`Routing: ${routingPreference}`);
// Warn about dual billing
if (providers.anthropic.dualBilling) {
console.warn('Both OAuth and API key active — may cause double billing');
} Example response:
{
"providers": {
"anthropic": {
"configured": true,
"authMethod": "api-key",
"hasKey": true,
"dualBilling": false,
"runtimes": [
{ "id": "claude-code", "name": "Claude Code", "status": "ready" },
{ "id": "anthropic-direct", "name": "Anthropic Direct", "status": "ready" }
]
},
"openai": {
"configured": false,
"hasKey": false,
"runtimes": [
{ "id": "openai-codex-app-server", "name": "Codex", "status": "not_configured" }
]
}
},
"routingPreference": "quality",
"configuredProviderCount": 1
} Get Anthropic Auth Settings
/api/settings Read current Anthropic authentication settings (key presence, auth method, API key source).
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| method | string | * | Auth method (oauth, api-key) |
| hasKey | boolean | * | Whether an API key is stored |
| apiKeySource | string | — | Key origin (manual, oauth, env) |
// Read current Anthropic auth settings
const res: Response = await fetch('http://localhost:3000/api/settings');
const auth: { method: string; hasKey: boolean; apiKeySource?: string } = await res.json();
console.log(`Auth method: ${auth.method}, key present: ${auth.hasKey}`); Example response:
{
"method": "api-key",
"hasKey": true,
"apiKeySource": "manual"
} Update Anthropic Auth Settings
/api/settings Update Anthropic authentication configuration. Validated with Zod.
Response 200 — Updated auth settings object
Set or rotate the Anthropic API key:
// Set or rotate the Anthropic API key
await fetch('http://localhost:3000/api/settings', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ apiKey: 'sk-ant-api03-...' }),
}); Errors: 400 — Zod validation failure
Get OpenAI Auth Settings
/api/settings/openai Read current OpenAI authentication settings.
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| hasKey | boolean | * | Whether an OpenAI API key is stored |
| apiKeySource | string | — | Key origin (manual, env) |
// Read current OpenAI auth settings
const res: Response = await fetch('http://localhost:3000/api/settings/openai');
const openai: { hasKey: boolean; apiKeySource?: string } = await res.json();
console.log(`OpenAI key present: ${openai.hasKey}`); Update OpenAI Auth Settings
/api/settings/openai Update OpenAI authentication configuration. Validated with Zod.
Response 200 — Updated OpenAI auth settings object
// Configure OpenAI for Codex runtime access
await fetch('http://localhost:3000/api/settings/openai', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ apiKey: 'sk-proj-...' }),
}); Errors: 400 — Zod validation failure
Budget Guardrails
Get Budget Snapshot
/api/settings/budgets Retrieve the current budget guardrail snapshot including limits and spend-to-date.
Check current spend against limits before queuing expensive tasks:
// Check budget before running a large task
const res: Response = await fetch('http://localhost:3000/api/settings/budgets');
const budget: {
dailyLimit: number; monthlyLimit: number;
dailySpend: number; monthlySpend: number;
alertThreshold: number;
} = await res.json();
console.log(`Daily: $${budget.dailySpend.toFixed(2)} / $${budget.dailyLimit.toFixed(2)}`);
console.log(`Monthly: $${budget.monthlySpend.toFixed(2)} / $${budget.monthlyLimit.toFixed(2)}`);
if (budget.dailySpend / budget.dailyLimit > 0.8) {
console.warn('Approaching daily budget limit');
} Example response:
{
"dailyLimit": 10.00,
"monthlyLimit": 200.00,
"dailySpend": 4.23,
"monthlySpend": 87.50,
"alertThreshold": 0.8,
"updatedAt": "2026-04-03T12:00:00.000Z"
} Update Budget Policy
/api/settings/budgets Set budget guardrail policy (daily/monthly limits, alert thresholds). Validated with Zod.
Response 200 — Updated budget snapshot
Set conservative budget limits for a team environment:
// Set budget guardrails
await fetch('http://localhost:3000/api/settings/budgets', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
dailyLimit: 10.00,
monthlyLimit: 200.00,
alertThreshold: 0.8, // warn at 80% usage
}),
}); Errors: 400 — Zod validation failure
Model Routing
Get Routing Preference
/api/settings/routing Read the current model routing preference.
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| preference | enum | * | cost, latency, quality, or manual |
// Read current routing preference
const res: Response = await fetch('http://localhost:3000/api/settings/routing');
const { preference }: { preference: string } = await res.json();
console.log(`Current routing: ${preference}`); Set Routing Preference
/api/settings/routing Update the model routing strategy.
Request Body
| Field | Type | Req | Description |
|---|---|---|---|
| preference | enum | * | One of: cost, latency, quality, manual |
Response 200 — { "preference": "<value>" }
Switch between routing strategies depending on your current needs:
// Switch to cost-optimized routing
await fetch('http://localhost:3000/api/settings/routing', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ preference: 'cost' }),
}); Errors: 400 — Invalid preference value
Pricing Registry
Get Pricing Snapshot
/api/settings/pricing Return the current pricing registry snapshot with per-model token costs.
View token pricing for all available models — useful for cost estimation before execution:
// Check model pricing for cost estimation
const res: Response = await fetch('http://localhost:3000/api/settings/pricing');
const pricing: { models: Array<{ modelId: string; inputPer1M: number; outputPer1M: number }> } = await res.json();
pricing.models.forEach((m) => {
console.log(`${m.modelId}: $${m.inputPer1M}/M input, $${m.outputPer1M}/M output`);
}); Example response:
{
"models": [
{ "modelId": "claude-sonnet-4-6-20250514", "inputPer1M": 3.00, "outputPer1M": 15.00 },
{ "modelId": "claude-haiku-4-20250414", "inputPer1M": 0.80, "outputPer1M": 4.00 }
],
"updatedAt": "2026-04-03T00:00:00.000Z"
} Refresh Pricing
/api/settings/pricing Force a refresh of the pricing registry from upstream sources.
Response 200 — Refreshed pricing snapshot
// Force a pricing refresh after provider announcements
const res: Response = await fetch('http://localhost:3000/api/settings/pricing', { method: 'POST' });
const pricing: { models: Array<{ modelId: string }> } = await res.json();
console.log(`Pricing updated: ${pricing.models.length} models`); Chat Settings
Get Chat Model
/api/settings/chat Read the default chat model.
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| defaultModel | string | * | Model ID used for new conversations |
// Read the default chat model
const res: Response = await fetch('http://localhost:3000/api/settings/chat');
const { defaultModel }: { defaultModel: string } = await res.json();
console.log(`Chat model: ${defaultModel}`); Set Chat Model
/api/settings/chat Update the default chat model.
Request Body
| Field | Type | Req | Description |
|---|---|---|---|
| defaultModel | string | * | Valid model ID from the supported models list |
Change the default model for new chat conversations:
// Switch the default chat model
await fetch('http://localhost:3000/api/settings/chat', {
method: 'PUT',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ defaultModel: 'claude-sonnet-4-6-20250514' }),
}); Errors: 400 — Invalid model ID
Runtime Settings
Get Runtime Config
/api/settings/runtime Read SDK timeout and max-turns settings for agent execution.
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| sdkTimeoutSeconds | string | * | SDK call timeout in seconds (default: 60) |
| maxTurns | string | * | Maximum agent turns per execution (default: 10) |
// Read SDK timeout and max-turns settings
const res: Response = await fetch('http://localhost:3000/api/settings/runtime');
const runtime: { sdkTimeoutSeconds: string; maxTurns: string } = await res.json();
console.log(`Timeout: ${runtime.sdkTimeoutSeconds}s, Max turns: ${runtime.maxTurns}`); Update Runtime Config
/api/settings/runtime Update SDK timeout and/or max-turns settings.
Request Body (all optional)
| Field | Type | Req | Description |
|---|---|---|---|
| sdkTimeoutSeconds | string | — | Timeout in seconds (10–300) |
| maxTurns | string | — | Max agent turns (1–50) |
Increase timeout and turns for complex tasks that need more agent interaction:
// Increase limits for complex agent tasks
await fetch('http://localhost:3000/api/settings/runtime', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sdkTimeoutSeconds: '120', maxTurns: '25' }),
}); Errors: 400 — Value out of range
Ollama Settings
Get Ollama Config
/api/settings/ollama Read Ollama connection settings.
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| baseUrl | string | * | Ollama server URL (default: http://localhost:11434) |
| defaultModel | string | * | Default model name (empty if not set) |
// Read Ollama connection settings
const res: Response = await fetch('http://localhost:3000/api/settings/ollama');
const ollama: { baseUrl: string; defaultModel: string } = await res.json();
console.log(`Ollama: ${ollama.baseUrl}, model: ${ollama.defaultModel || '(not set)'}`); Update Ollama Config
/api/settings/ollama Update Ollama base URL and/or default model.
Request Body (all optional)
| Field | Type | Req | Description |
|---|---|---|---|
| baseUrl | string | — | Ollama server URL |
| defaultModel | string | — | Default model name |
Configure a local Ollama instance for offline agent execution:
// Point to a local Ollama instance
await fetch('http://localhost:3000/api/settings/ollama', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ baseUrl: 'http://localhost:11434', defaultModel: 'llama3.1' }),
}); Learning Context
Get Learning Settings
/api/settings/learning Read the learning context character limit.
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| contextCharLimit | string | * | Max characters for learning context (default: 8000) |
// Read the learning context character limit
const res: Response = await fetch('http://localhost:3000/api/settings/learning');
const { contextCharLimit }: { contextCharLimit: string } = await res.json();
console.log(`Learning context limit: ${Number(contextCharLimit).toLocaleString()} chars`); Update Learning Settings
/api/settings/learning Update the learning context character limit.
Request Body
| Field | Type | Req | Description |
|---|---|---|---|
| contextCharLimit | string | * | Limit in characters (2,000–32,000, step 1,000) |
Increase the learning context window so agents retain more project-specific knowledge:
// Double the learning context window
await fetch('http://localhost:3000/api/settings/learning', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ contextCharLimit: '16000' }),
}); Errors: 400 — Value out of range or not a multiple of 1,000
Browser Tools
Get Browser Tool Settings
/api/settings/browser-tools Read MCP browser tool enablement and configuration.
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| chromeDevtoolsEnabled | boolean | * | Whether Chrome DevTools MCP is enabled |
| playwrightEnabled | boolean | * | Whether Playwright MCP is enabled |
| chromeDevtoolsConfig | string | * | Chrome DevTools MCP config (JSON string or empty) |
| playwrightConfig | string | * | Playwright MCP config (JSON string or empty) |
// Read browser tool enablement
const res: Response = await fetch('http://localhost:3000/api/settings/browser-tools');
const tools: { chromeDevtoolsEnabled: boolean; playwrightEnabled: boolean } = await res.json();
console.log(`Chrome DevTools: ${tools.chromeDevtoolsEnabled ? 'on' : 'off'}`);
console.log(`Playwright: ${tools.playwrightEnabled ? 'on' : 'off'}`); Update Browser Tool Settings
/api/settings/browser-tools Enable/disable browser tools and update their MCP configurations.
Request Body (all optional)
| Field | Type | Req | Description |
|---|---|---|---|
| chromeDevtoolsEnabled | boolean | — | Toggle Chrome DevTools MCP |
| playwrightEnabled | boolean | — | Toggle Playwright MCP |
| chromeDevtoolsConfig | string | — | Chrome DevTools MCP config JSON |
| playwrightConfig | string | — | Playwright MCP config JSON |
Enable Chrome DevTools for agents that need browser automation:
// Enable Chrome DevTools MCP for browser-based tasks
await fetch('http://localhost:3000/api/settings/browser-tools', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
chromeDevtoolsEnabled: true,
playwrightEnabled: false,
}),
}); Web Search
Get Web Search Settings
/api/settings/web-search Read Exa web search MCP enablement.
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| exaSearchEnabled | boolean | * | Whether Exa Search MCP is enabled |
// Read Exa web search enablement
const res: Response = await fetch('http://localhost:3000/api/settings/web-search');
const { exaSearchEnabled }: { exaSearchEnabled: boolean } = await res.json();
console.log(`Web search: ${exaSearchEnabled ? 'enabled' : 'disabled'}`); Update Web Search Settings
/api/settings/web-search Enable or disable Exa web search MCP.
Request Body
| Field | Type | Req | Description |
|---|---|---|---|
| exaSearchEnabled | boolean | * | Toggle Exa Search MCP |
// Enable web search for research-oriented agents
await fetch('http://localhost:3000/api/settings/web-search', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ exaSearchEnabled: true }),
}); Utility
Get Default Author
Test Runtime Connection
/api/settings/test Test connectivity to a specific agent runtime. Returns connection status and runtime capabilities.
Request Body
| Field | Type | Req | Description |
|---|---|---|---|
| runtime | string | — | Runtime ID to test (default: system default runtime) |
Response Body
| Field | Type | Req | Description |
|---|---|---|---|
| connected | boolean | * | Whether the runtime responded successfully |
| runtime | string | * | Runtime ID that was tested |
| capabilities | object | * | Runtime capability flags |
| error | string | — | Error message if connection failed |
Test connectivity before running tasks — helpful for diagnosing configuration issues:
// Test runtime connectivity
const res: Response = await fetch('http://localhost:3000/api/settings/test', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ runtime: 'claude-code' }),
});
const result: { connected: boolean; runtime: string; capabilities: Record<string, any>; error?: string } = await res.json();
if (result.connected) {
console.log(`${result.runtime} is ready`);
console.log('Capabilities:', result.capabilities);
} else {
console.error(`Connection failed: ${result.error}`);
} Example response:
{
"connected": true,
"runtime": "claude-code",
"capabilities": {
"streaming": true,
"toolUse": true,
"maxTokens": 128000
}
} Routing Preferences
| Value | Description |
|---|---|
| cost | Route to the cheapest available model that meets the task requirements. |
| latency | Route to the fastest responding model. |
| quality | Route to the highest capability model. |
| manual | User explicitly selects the model per task. |