Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.speko.dev/llms.txt

Use this file to discover all available pages before exploring further.

An Agent is a persisted persona record on Speko. It bundles the values you’d otherwise have to repeat on every session create:
  • systemPrompt — the agent’s instructions
  • voice — TTS voice id (provider-specific)
  • intentlanguage and optional optimizeFor (latency / quality / cost)
  • llmOptions — optional temperature, maxTokens, model
  • stackPreferences — optional per-layer allowlists (which STT / LLM / TTS providers the router is allowed to pick)
Once created, an agent is referenced by id (e.g. agent_a1b2c3d4e5f60718) when starting a voice session. Per-call body fields still override the agent’s stored defaults — agents are sensible defaults, not a wall.

When to use an agent

Use one when the same persona is starting more than one session — that is, almost always in production. Without an agent, every POST /v1/sessions ships the full config inline; with an agent, you ship just { agentId }.
- POST /v1/sessions
- { "intent": { "language": "en" }, "voice": "...", "systemPrompt": "...", ... }
+ POST /v1/sessions
+ { "agentId": "agent_a1b2c3d4e5f60718" }
Per-call overrides are still allowed and still win, so you can pin the persona without giving up per-call tweaks (a different voice for a single VIP user, a longer system prompt for a high-stakes call, etc.).

Stack preferences

Speko’s default behavior is auto-routing — for each session, the highest-scoring provider per pipeline layer (STT, LLM, TTS) is picked from every benchmarked option. Stack preferences narrow that pool per agent, so you can express opinions like “this agent’s STT must be Deepgram or AssemblyAI” or “LLM must be OpenAI or Anthropic” without giving up auto-routing or failover within the allowed set.
{
  "stackPreferences": {
    "allowedProviders": {
      "stt": ["deepgram", "assemblyai"],
      "llm": ["openai", "anthropic"],
      "tts": ["cartesia", "elevenlabs"]
    }
  }
}

Vendor vs model entries

Each entry in an allowedProviders list is either a vendor id (allow any model from that vendor) or "<vendor>:<model>" (allow only that specific model). Both forms can be mixed in the same array. Failover stays active across all entries in the layer.
{
  "stackPreferences": {
    "allowedProviders": {
      "stt": ["deepgram:nova-3", "assemblyai"],
      "llm": ["openai:gpt-5", "anthropic"],
      "tts": ["elevenlabs:eleven_flash_v2_5"]
    }
  }
}
Reading that example: STT must be Deepgram’s Nova-3 specifically, or any model from AssemblyAI. LLM must be OpenAI’s GPT-5 specifically, or any model from Anthropic. TTS must be ElevenLabs’ eleven_flash_v2_5 and nothing else. ["deepgram:nova-3", "deepgram:nova-2"] is also valid — that pins to two specific Deepgram models, with no fallback to other Deepgram models within the vendor (failover to other allowed vendors still applies). Use GET /v1/providers/known to enumerate every (vendor, model) pair the router knows about — the id field on each entry is the verbatim string to put here. Rules of thumb:
  • Empty / missing layer = no constraint. A stt allowlist of [] (or absent entirely) means the router has full freedom for STT.
  • Failover stays active within the allowed set. If you allowlist Deepgram + AssemblyAI for STT, and Deepgram errors mid-call, the router will fail over to AssemblyAI rather than to a non-allowed provider. The same holds across model-level entries — ["deepgram:nova-3", "assemblyai"] will fail over from Nova-3 to AssemblyAI.
  • Per-call overrides win per layer. When you start a session with both an agentId and an inline constraints.allowedProviders.stt, the per-call stt list replaces the agent’s stt list — but the agent’s llm and tts lists still apply unless those are also overridden.
  • Empty allowlist with no fallback fails to route. If you allowlist a provider that has no benchmark data, the router can’t rank it; the session will error rather than silently picking an alternative.
Stack preferences are configured per agent — either via the dashboard’s Stack preferences section on the Persona tab, or via stackPreferences in POST /v1/agents / PATCH /v1/agents/{id}.

Session history

Every session started with agentId (whether via POST /v1/sessions directly or via the SDK’s VoiceConversation.create({ agentId })) is linked to that agent at create time. The dashboard surfaces them under the Sessions tab on the agent’s detail page; the API equivalent is GET /v1/sessions?agent=<id>, which scopes the standard sessions list down to that agent’s calls and combines with the existing cursor, status, kind, and limit filters. The link is read-only — sessions are not retroactively attached to an agent, only at create time.

Tools live under agents

Every tool you register is scoped to a specific agent — the unique key is (organization, agentId, toolName). This means:
  • Different agents in the same org can register tools with the same name (lookup_user, book_appointment) without colliding.
  • Adding a tool to one agent doesn’t expose it to your other agents.
  • The voice worker fetches GET /v1/agents/{agentId}/tools at session start to assemble the tool list.
Manage tools from the Tools tab inside an agent’s detail page in the dashboard, or via the /v1/agents/{id}/tools API.

Lifecycle

OperationEndpointNotes
CreatePOST /v1/agentsReturns the new id. Names are unique per organization.
ListGET /v1/agentsReturns every agent in the calling key’s organization.
ReadGET /v1/agents/{id}404 if not found / not in your org.
UpdatePATCH /v1/agents/{id}Partial — send only the fields you want to change.
DeleteDELETE /v1/agents/{id}Cascades to tools. The Default agent cannot be deleted.

The Default agent

When your organization is created, Speko seeds a single agent named Default so you have something to point at on day one. It’s a regular agent in every other respect — edit its system prompt, voice, and intent freely. It’s only special in two ways: it can’t be renamed, and it can’t be deleted.

Where to next

Browser SDK

VoiceConversation.create({ agentId }) — browser-side WebRTC against your agent.

Dashboard

Manage agents and their tools from the web dashboard.

API reference

Full request/response shapes for the /v1/agents endpoints.