Speko Docs

Quickstart

Mint a router key, then call chat, speech, and transcription through the OpenAI SDK you already use.

1. Mint a router key

Open platform.speko.ai/router/keys and click Create key. The create page is one sentence - a language, an optional accent, a use case, and an objective - over the stack the router resolves live for that policy. The defaults already make a valid policy, so create straight away or refine first: each stage either follows the live ranking on Auto or is pinned to an ordered failover chain with Pin.

There is no name field. The key names itself from the policy - en-phone-balanced, es-mx-phone-latency - and the name appears once, at reveal, next to the key value.

The value is shown exactly once, at creation. Copy it now; Speko will not show it again. The reveal hands you SPEKO_API_KEY and SPEKO_BASE_URL as ready-to-paste env lines - for this walkthrough, export both:

export SPEKO_API_KEY=sk_live_...   # shown once, at creation
export SPEKO_BASE_URL=https://api.speko.ai/v1

Routing is not locked in: the key's page doubles as its detail, and the policy stays editable after creation - editing it never renames the key. Details in keys and policy.

2. Point your client at the router

The router is OpenAI-compatible, so the official SDKs work unchanged. Two values change: the base URL and the key.

import os

from openai import OpenAI

client = OpenAI(
    api_key=os.environ["SPEKO_API_KEY"],
    base_url="https://api.speko.ai/v1",
)
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.SPEKO_API_KEY,
  baseURL: 'https://api.speko.ai/v1',
});

The /v1 suffix is part of the base URL. Both the Python and TypeScript SDKs append paths to whatever you give them, so https://api.speko.ai (without /v1) sends requests to /chat/completions and gets a 404. This is the most common setup failure.

3. Complete a turn

model: "auto" hands model choice to the router. It ranks the live LLM candidates for your key's language and objective and calls the winner.

curl -X POST https://api.speko.ai/v1/chat/completions \
  -H "Authorization: Bearer $SPEKO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "auto",
    "messages": [
      { "role": "system", "content": "You are a scheduling assistant. Answer in one sentence." },
      { "role": "user", "content": "Move my Thursday dentist appointment to Friday morning." }
    ]
  }'
import os

from openai import OpenAI

client = OpenAI(
    api_key=os.environ["SPEKO_API_KEY"],
    base_url="https://api.speko.ai/v1",
)

completion = client.chat.completions.create(
    model="auto",
    messages=[
        {"role": "system", "content": "You are a scheduling assistant. Answer in one sentence."},
        {"role": "user", "content": "Move my Thursday dentist appointment to Friday morning."},
    ],
)

print(completion.choices[0].message.content)
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.SPEKO_API_KEY,
  baseURL: 'https://api.speko.ai/v1',
});

const completion = await client.chat.completions.create({
  model: 'auto',
  messages: [
    { role: 'system', content: 'You are a scheduling assistant. Answer in one sentence.' },
    { role: 'user', content: 'Move my Thursday dentist appointment to Friday morning.' },
  ],
});

console.log(completion.choices[0].message.content);

To see which provider actually served the request, read the x-route response header. It carries Provider/model.

4. Synthesize speech

response_format: "pcm" returns raw 24 kHz mono 16-bit signed little-endian PCM — no container, no header — which is what a telephony or WebRTC pipeline wants. Ask for wav when you need a file a player can open on its own; mp3 and opus are refused, and TTS (batch) says why.

curl -X POST https://api.speko.ai/v1/audio/speech \
  -H "Authorization: Bearer $SPEKO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "auto",
    "input": "Your appointment is confirmed for Friday at nine in the morning.",
    "response_format": "pcm"
  }' \
  --output confirmation.pcm
import os

from openai import OpenAI

client = OpenAI(
    api_key=os.environ["SPEKO_API_KEY"],
    base_url="https://api.speko.ai/v1",
)

response = client.audio.speech.create(
    model="auto",
    input="Your appointment is confirmed for Friday at nine in the morning.",
    response_format="pcm",
)

with open("confirmation.pcm", "wb") as f:
    f.write(response.read())
import { writeFile } from 'node:fs/promises';
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.SPEKO_API_KEY,
  baseURL: 'https://api.speko.ai/v1',
});

const response = await client.audio.speech.create({
  model: 'auto',
  input: 'Your appointment is confirmed for Friday at nine in the morning.',
  response_format: 'pcm',
});

await writeFile('confirmation.pcm', Buffer.from(await response.arrayBuffer()));

That is the batch path — one request, the finished utterance. When a listener is waiting on the first word, stream it instead and play as it decodes.

5. Transcribe audio

curl -X POST https://api.speko.ai/v1/audio/transcriptions \
  -H "Authorization: Bearer $SPEKO_API_KEY" \
  -F model=auto \
  -F file=@support-call.wav
import os

from openai import OpenAI

client = OpenAI(
    api_key=os.environ["SPEKO_API_KEY"],
    base_url="https://api.speko.ai/v1",
)

with open("support-call.wav", "rb") as f:
    transcript = client.audio.transcriptions.create(model="auto", file=f)

print(transcript.text)
import { createReadStream } from 'node:fs';
import OpenAI from 'openai';

const client = new OpenAI({
  apiKey: process.env.SPEKO_API_KEY,
  baseURL: 'https://api.speko.ai/v1',
});

const transcript = await client.audio.transcriptions.create({
  model: 'auto',
  file: createReadStream('support-call.wav'),
});

console.log(transcript.text);

That is the batch path — one finished file, one transcript. When audio is still arriving, open a socket instead and get partials as the speaker talks.

On this page