Types
Shared request / response types exported from @spekoai/sdk.
All types below are exported from the package root:
import type {
SpekoClientOptions,
KeySource,
OptimizeFor,
RoutingIntent,
PipelineConstraints,
TranscribeOptions,
TranscribeResult,
TranscribeStreamEvent,
SynthesizeOptions,
SynthesizeResult,
SynthesizeStreamResult,
ChatMessage,
ChatTool,
ChatToolCall,
ChatToolChoice,
CompleteParams,
CompleteResult,
CompleteStreamEvent,
UsageSummary,
UsageByProvider,
UsageQueryParams,
OrganizationBalance,
CreditLedgerEntry,
CreditLedgerKind,
CreditLedgerPage,
CreditLedgerQueryParams,
RealtimeProvider,
RealtimeToolSpec,
RealtimeConnectParams,
RealtimeFrame,
RealtimeEventHandler,
RealtimeSessionHandle,
VoiceDialParams,
VoiceDialResult,
PhoneNumberRow,
PhoneNumberKybOverview,
PhoneNumberKybSubmission,
CallDetail,
CallEvent,
CallReport,
CallTransfer,
ScheduledCallback,
AgentCallListPage,
AgentRow,
AgentCreateParams,
AgentToolRow,
KnowledgeBaseRow,
KnowledgeBaseDocumentRow,
} from '@spekoai/sdk';Routing primitives
OptimizeFor
type OptimizeFor = 'balanced' | 'accuracy' | 'latency' | 'cost';Biases the weighted score the router uses to rank candidates. balanced is the default.
RoutingIntent
interface RoutingIntent {
language: string; // BCP-47, e.g. "en" or "es-MX"
region?: string; // e.g. "us-east4"; defaults to "global" server-side
optimizeFor?: OptimizeFor;
}Every proxy call takes one. TranscribeOptions and SynthesizeOptions extend it directly.
PipelineConstraints
interface PipelineConstraints {
allowedProviders?: {
stt?: string[];
llm?: string[];
tts?: string[];
};
}Optional allow-list layered on top of RoutingIntent. When set, the router still ranks by benchmark score but considers only candidates in the allow-list for that modality.
Transcribe
interface TranscribeOptions extends RoutingIntent {
contentType?: string; // default "audio/wav"
constraints?: PipelineConstraints;
keywords?: readonly string[];
}
interface TranscribeResult {
text: string;
provider: string;
model: string;
confidence: number | null;
failoverCount: number;
scoresRunId: string | null;
}Synthesize
interface SynthesizeOptions extends RoutingIntent {
voice?: string;
speed?: number;
constraints?: PipelineConstraints;
}
interface SynthesizeResult {
audio: Uint8Array;
contentType: string; // e.g. "audio/pcm;rate=24000" or "audio/mpeg"
provider: string;
model: string;
failoverCount: number;
scoresRunId: string | null;
}Complete
interface ChatMessage {
role: 'system' | 'user' | 'assistant' | 'tool';
content: string;
toolCalls?: ChatToolCall[];
toolCallId?: string;
isError?: boolean;
}
interface ChatToolCall {
id: string;
name: string;
args: string;
}
type ChatToolChoice =
| 'auto'
| 'none'
| 'required'
| { type: 'function'; function: { name: string } };
interface ChatTool {
name: string;
description: string;
parameters: Record<string, unknown>;
executionMode?: 'inline' | 'webhook' | 'builtin';
source?:
| { kind: 'inline' }
| {
kind: 'webhook';
url: string;
secretRef: string;
headers?: Record<string, string>;
timeoutMs?: number;
}
| { kind: 'builtin'; name: string; config?: unknown };
}
interface CompleteParams {
messages: ChatMessage[];
intent: RoutingIntent;
systemPrompt?: string;
temperature?: number;
maxTokens?: number;
reasoningEffort?: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
constraints?: PipelineConstraints;
tools?: ChatTool[];
toolChoice?: ChatToolChoice;
parallelToolCalls?: boolean;
maxToolHops?: number;
}
interface CompleteResult {
text: string;
provider: string;
model: string;
usage: {
promptTokens: number;
completionTokens: number;
};
failoverCount: number;
scoresRunId: string | null;
toolCalls?: ChatToolCall[];
}Usage
type KeySource = 'BYOK' | 'MANAGED';
interface UsageQueryParams {
from?: string; // ISO-8601
to?: string; // ISO-8601
}
interface UsageSummary {
totalSessions: number;
totalMinutes: number;
totalCost: number;
breakdown: UsageByProvider[];
balanceUsd: number;
currency: 'USD';
}
interface UsageByProvider {
provider: string;
type: 'stt' | 'llm' | 'tts';
metric: string;
keySource: KeySource;
quantity: number;
cost: number;
}Credits
interface OrganizationBalance {
balanceUsd: number;
currency: 'USD';
updatedAt: string;
}
type CreditLedgerKind = 'grant' | 'debit' | 'topup' | 'refund' | 'adjustment';
interface CreditLedgerEntry {
id: string;
kind: CreditLedgerKind;
/** Signed. Positive for grants/topups/refunds, negative for debits. */
amountMicroUsd: string;
metric: string | null;
provider: string | null;
sessionId: string | null;
createdAt: string;
}
interface CreditLedgerPage {
entries: CreditLedgerEntry[];
nextCursor: string | null;
}
interface CreditLedgerQueryParams {
limit?: number;
cursor?: string;
}Realtime (S2S)
type RealtimeProvider = 'openai' | 'google' | 'xai' | 'inworld';
interface RealtimeToolSpec {
name: string;
description: string;
parameters: Record<string, unknown>;
}
interface RealtimeConnectParams {
provider: RealtimeProvider;
model: string;
voice?: string;
systemPrompt?: string;
temperature?: number;
inputSampleRate?: 16000 | 24000;
outputSampleRate?: 16000 | 24000;
tools?: RealtimeToolSpec[];
metadata?: Record<string, unknown>;
/** Max session duration in seconds. Server-capped at 1800 (30 min). */
ttlSeconds?: number;
}
type RealtimeFrame =
| { type: 'ready'; inputSampleRate: 16000 | 24000; outputSampleRate: 16000 | 24000 }
| { type: 'audio'; pcm: Uint8Array; sampleRate: number }
| {
type: 'transcript';
role: 'user' | 'assistant';
text: string;
final: boolean;
}
| {
type: 'tool_call';
callId: string;
name: string;
arguments: string;
}
| {
type: 'usage';
inputAudioTokens: number;
outputAudioTokens: number;
}
| { type: 'interruption'; at: 'user' | 'assistant' }
| {
type: 'server_tool_call';
id: string;
name: string;
status: 'started' | 'completed' | 'failed';
}
| { type: 'error'; code: string; message: string }
| { type: 'close'; code: number; reason: string };
type RealtimeEventHandler = (frame: RealtimeFrame) => void;
interface RealtimeSessionHandle {
readonly sessionId: string;
readonly expiresAt: string;
readonly inputSampleRate: 16000 | 24000;
readonly outputSampleRate: 16000 | 24000;
sendAudio(pcm: Uint8Array): void;
commit(): void;
interrupt(): void;
sendToolResult(callId: string, output: string): void;
on(handler: RealtimeEventHandler): () => void;
close(code?: number, reason?: string): void;
}Voice, Phone Numbers, Agents, and Knowledge Bases
These resource types are also exported from the package root. The full shapes live in TypeScript and are intended to be consumed from your editor, but the high-level entry points are:
interface VoiceDialParams {
to: string;
from?: string;
intent: RoutingIntent;
constraints?: PipelineConstraints;
voice?: string;
systemPrompt?: string;
llm?: { temperature?: number; maxTokens?: number };
ttsOptions?: { sampleRate?: number; speed?: number };
metadata?: Record<string, unknown>;
}
interface VoiceDialResult {
sessionId: string;
callControlId: string;
roomName: string;
status: 'dialing' | 'dialing-stub';
to: string;
from: string;
}
interface PhoneNumberRow {
id: string;
e164: string;
direction: 'inbound' | 'outbound' | 'both';
label: string | null;
agentId: string | null;
createdAt: string;
updatedAt: string;
}
interface AgentRow {
id: string;
name: string;
systemPrompt: string;
voice: string | null;
intent: { language: string; optimizeFor?: 'latency' | 'quality' | 'cost' };
llmOptions: { temperature?: number; maxTokens?: number; model?: string } | null;
stackPreferences: {
allowedProviders?: { stt?: string[]; llm?: string[]; tts?: string[]; s2s?: string[] };
} | null;
sttOptions: { keywords?: string[] } | null;
createdAt: string;
updatedAt: string;
}
interface KnowledgeBaseRow {
id: string;
agentId: string;
name: string;
description: string | null;
embeddingModel: string;
documentCount: number;
chunkCount: number;
createdAt: string;
updatedAt: string;
}Client
interface SpekoClientOptions {
apiKey: string;
baseUrl?: string; // default "https://api.speko.dev"
timeout?: number; // default 30000
}