@spekoai/sdk 0.4.3 → 0.5.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/README.md +88 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/lib/client.d.ts +13 -1
- package/dist/lib/client.d.ts.map +1 -1
- package/dist/lib/client.js +22 -2
- package/dist/lib/http.d.ts +12 -4
- package/dist/lib/http.d.ts.map +1 -1
- package/dist/lib/http.js +31 -14
- package/dist/lib/resources/agents.d.ts +12 -2
- package/dist/lib/resources/agents.d.ts.map +1 -1
- package/dist/lib/resources/agents.js +12 -4
- package/dist/lib/resources/calls.d.ts +19 -1
- package/dist/lib/resources/calls.d.ts.map +1 -1
- package/dist/lib/resources/calls.js +22 -0
- package/dist/lib/resources/knowledge-bases.d.ts +1 -1
- package/dist/lib/resources/knowledge-bases.js +1 -1
- package/dist/lib/resources/phone-numbers.d.ts +2 -1
- package/dist/lib/resources/phone-numbers.d.ts.map +1 -1
- package/dist/lib/resources/phone-numbers.js +2 -1
- package/dist/lib/resources/realtime.d.ts +3 -5
- package/dist/lib/resources/realtime.d.ts.map +1 -1
- package/dist/lib/resources/realtime.js +829 -91
- package/dist/lib/resources/sessions.d.ts +53 -0
- package/dist/lib/resources/sessions.d.ts.map +1 -0
- package/dist/lib/resources/sessions.js +166 -0
- package/dist/lib/resources/sms.d.ts +80 -0
- package/dist/lib/resources/sms.d.ts.map +1 -0
- package/dist/lib/resources/sms.js +152 -0
- package/dist/lib/resources/synthesize.d.ts.map +1 -1
- package/dist/lib/resources/synthesize.js +12 -6
- package/dist/lib/resources/transcribe.d.ts.map +1 -1
- package/dist/lib/resources/transcribe.js +9 -2
- package/dist/lib/resources/voice.d.ts +283 -1
- package/dist/lib/resources/voice.d.ts.map +1 -1
- package/dist/lib/resources/voice.js +345 -0
- package/dist/lib/resources/webhooks.d.ts +25 -0
- package/dist/lib/resources/webhooks.d.ts.map +1 -0
- package/dist/lib/resources/webhooks.js +46 -0
- package/dist/lib/types/index.d.ts +998 -9
- package/dist/lib/types/index.d.ts.map +1 -1
- package/dist/lib/voice-contract.d.ts +280 -0
- package/dist/lib/voice-contract.d.ts.map +1 -0
- package/dist/lib/voice-contract.js +115 -0
- package/package.json +2 -1
- package/src/index.ts +212 -0
- package/src/lib/client.ts +169 -0
- package/src/lib/errors.ts +28 -0
- package/src/lib/http.ts +442 -0
- package/src/lib/resources/agents.ts +211 -0
- package/src/lib/resources/callbacks.ts +40 -0
- package/src/lib/resources/calls.ts +113 -0
- package/src/lib/resources/complete.ts +63 -0
- package/src/lib/resources/credits.ts +41 -0
- package/src/lib/resources/knowledge-bases.ts +199 -0
- package/src/lib/resources/phone-numbers.ts +109 -0
- package/src/lib/resources/realtime-globals.d.ts +31 -0
- package/src/lib/resources/realtime.spec.ts +565 -0
- package/src/lib/resources/realtime.ts +1169 -0
- package/src/lib/resources/sessions.ts +191 -0
- package/src/lib/resources/sms.ts +214 -0
- package/src/lib/resources/synthesize.ts +101 -0
- package/src/lib/resources/transcribe.ts +91 -0
- package/src/lib/resources/usage.ts +24 -0
- package/src/lib/resources/voice.ts +426 -0
- package/src/lib/resources/voices.ts +32 -0
- package/src/lib/resources/webhooks.ts +67 -0
- package/src/lib/types/index.ts +2409 -0
- package/src/lib/voice-contract.ts +358 -0
|
@@ -0,0 +1,2409 @@
|
|
|
1
|
+
import type {
|
|
2
|
+
CallDirection,
|
|
3
|
+
CallJoinCredentials,
|
|
4
|
+
CallResource,
|
|
5
|
+
CallStatus,
|
|
6
|
+
} from '../voice-contract.js';
|
|
7
|
+
|
|
8
|
+
/** Options for creating a Speko client. */
|
|
9
|
+
export interface SpekoClientOptions {
|
|
10
|
+
/** API key for authentication. */
|
|
11
|
+
apiKey: string;
|
|
12
|
+
/** Org-defined broker identity used by human-calling methods. */
|
|
13
|
+
brokerId?: string;
|
|
14
|
+
/** Base URL of the Speko API. Defaults to https://api.speko.dev */
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
/** Alias for {@link SpekoClientOptions.baseUrl}. If both are set, `baseUrl` wins. */
|
|
17
|
+
baseURL?: string;
|
|
18
|
+
/** Request timeout in milliseconds. Defaults to 30000. */
|
|
19
|
+
timeout?: number;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/** BYOK = customer key, no Speko charge. MANAGED = platform key, billed. */
|
|
23
|
+
export type KeySource = 'BYOK' | 'MANAGED';
|
|
24
|
+
|
|
25
|
+
/** Usage record for a workspace. */
|
|
26
|
+
export interface UsageSummary {
|
|
27
|
+
totalSessions: number;
|
|
28
|
+
totalMinutes: number;
|
|
29
|
+
totalCost: number;
|
|
30
|
+
breakdown: UsageByProvider[];
|
|
31
|
+
balanceUsd: number;
|
|
32
|
+
currency: 'USD';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface UsageByProvider {
|
|
36
|
+
provider: string;
|
|
37
|
+
type: 'stt' | 'llm' | 'tts';
|
|
38
|
+
metric: string;
|
|
39
|
+
keySource: KeySource;
|
|
40
|
+
quantity: number;
|
|
41
|
+
cost: number;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/** Parameters for querying usage. */
|
|
45
|
+
export interface UsageQueryParams {
|
|
46
|
+
/** Start date (ISO 8601). */
|
|
47
|
+
from?: string;
|
|
48
|
+
/** End date (ISO 8601). */
|
|
49
|
+
to?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/** Current prepaid credit balance. */
|
|
53
|
+
export interface OrganizationBalance {
|
|
54
|
+
balanceUsd: number;
|
|
55
|
+
currency: 'USD';
|
|
56
|
+
updatedAt: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type CreditLedgerKind = 'grant' | 'debit' | 'topup' | 'refund' | 'adjustment';
|
|
60
|
+
|
|
61
|
+
export interface CreditLedgerEntry {
|
|
62
|
+
id: string;
|
|
63
|
+
kind: CreditLedgerKind;
|
|
64
|
+
/** Signed. Positive for grants/topups/refunds, negative for debits. */
|
|
65
|
+
amountMicroUsd: string;
|
|
66
|
+
metric: string | null;
|
|
67
|
+
provider: string | null;
|
|
68
|
+
sessionId: string | null;
|
|
69
|
+
createdAt: string;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export interface CreditLedgerPage {
|
|
73
|
+
entries: CreditLedgerEntry[];
|
|
74
|
+
/** Pass back as `cursor` for the next page, or null if exhausted. */
|
|
75
|
+
nextCursor: string | null;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface CreditLedgerQueryParams {
|
|
79
|
+
limit?: number;
|
|
80
|
+
cursor?: string;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// --- Routing primitives -----------------------------------------------------
|
|
84
|
+
|
|
85
|
+
/** Optimization preset that biases the router's weighted score. */
|
|
86
|
+
export type OptimizeFor = 'balanced' | 'accuracy' | 'latency' | 'cost';
|
|
87
|
+
|
|
88
|
+
/** Routing intent passed to the proxy primitives. */
|
|
89
|
+
export interface RoutingIntent {
|
|
90
|
+
/** BCP-47 language tag, e.g. "en" or "es-MX". */
|
|
91
|
+
language: string;
|
|
92
|
+
/**
|
|
93
|
+
* Region to rank streaming providers in (e.g. `"us-east4"`, `"eu-west1"`).
|
|
94
|
+
* Defaults to `"global"` on the server, which surfaces region-agnostic
|
|
95
|
+
* (batch) benchmark rows. Set this when latency to a specific
|
|
96
|
+
* geography matters — STT/TTS rankings differ per region.
|
|
97
|
+
*/
|
|
98
|
+
region?: string;
|
|
99
|
+
optimizeFor?: OptimizeFor;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Optional constraints layered on top of `RoutingIntent`. The router still
|
|
104
|
+
* ranks candidates by benchmark score — but if `allowedProviders[modality]`
|
|
105
|
+
* is set and non-empty, it only considers that subset.
|
|
106
|
+
*/
|
|
107
|
+
export interface PipelineConstraints {
|
|
108
|
+
allowedProviders?: {
|
|
109
|
+
stt?: string[];
|
|
110
|
+
llm?: string[];
|
|
111
|
+
tts?: string[];
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// --- Transcribe -------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
export interface TranscribeOptions extends RoutingIntent {
|
|
118
|
+
/**
|
|
119
|
+
* Optional voice/session identifier forwarded as `x-session-id` for usage
|
|
120
|
+
* attribution. The value is carried out-of-band so request bodies and STT
|
|
121
|
+
* provider options stay provider-shaped.
|
|
122
|
+
*/
|
|
123
|
+
sessionId?: string;
|
|
124
|
+
/** MIME type of the audio body. Defaults to "audio/wav". */
|
|
125
|
+
contentType?: string;
|
|
126
|
+
constraints?: PipelineConstraints;
|
|
127
|
+
/**
|
|
128
|
+
* Domain keywords to bias the STT toward. Forwarded to whichever provider
|
|
129
|
+
* the router picks: Deepgram → `keywords`, AssemblyAI → `keyterms_prompt`
|
|
130
|
+
* (or `word_boost` on legacy models), OpenAI Whisper → comma-joined prompt,
|
|
131
|
+
* ElevenLabs Scribe → `biased_keywords`. Casing matters for proper nouns.
|
|
132
|
+
*/
|
|
133
|
+
keywords?: readonly string[];
|
|
134
|
+
/** Provider-facing STT overrides. Routing continues to use the inherited language. */
|
|
135
|
+
sttOptions?: { language?: string };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export interface TranscribeResult {
|
|
139
|
+
text: string;
|
|
140
|
+
provider: string;
|
|
141
|
+
model: string;
|
|
142
|
+
confidence: number | null;
|
|
143
|
+
failoverCount: number;
|
|
144
|
+
scoresRunId: string | null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
export type TranscribeStreamEvent =
|
|
148
|
+
| {
|
|
149
|
+
type: 'meta';
|
|
150
|
+
provider: string;
|
|
151
|
+
model: string;
|
|
152
|
+
failoverCount: number;
|
|
153
|
+
scoresRunId: string | null;
|
|
154
|
+
}
|
|
155
|
+
| {
|
|
156
|
+
type: 'transcript';
|
|
157
|
+
text: string;
|
|
158
|
+
isFinal: boolean;
|
|
159
|
+
confidence: number;
|
|
160
|
+
}
|
|
161
|
+
| (TranscribeResult & { type: 'done' })
|
|
162
|
+
| { type: 'error'; error: string; code: string };
|
|
163
|
+
|
|
164
|
+
// --- Synthesize -------------------------------------------------------------
|
|
165
|
+
|
|
166
|
+
export interface SynthesizeOptions extends RoutingIntent {
|
|
167
|
+
/**
|
|
168
|
+
* Optional voice/session identifier forwarded as `x-session-id` for usage
|
|
169
|
+
* attribution. The value is carried out-of-band so request bodies and TTS
|
|
170
|
+
* provider options stay provider-shaped.
|
|
171
|
+
*/
|
|
172
|
+
sessionId?: string;
|
|
173
|
+
/** Optional voice override. Otherwise the SDK uses each provider's default. */
|
|
174
|
+
voice?: string;
|
|
175
|
+
/**
|
|
176
|
+
* Optional upstream model name to use for synthesis (e.g.
|
|
177
|
+
* `eleven_multilingual_v2`, `sonic-2`, `gpt-4o-mini-tts`,
|
|
178
|
+
* `qwen3-tts-flash`). When omitted, the router picks the best-ranked
|
|
179
|
+
* model for the chosen provider. When set, applies to the primary
|
|
180
|
+
* candidate only — failover candidates still use the selector's model
|
|
181
|
+
* so a model intended for provider A isn't sent to provider B.
|
|
182
|
+
*/
|
|
183
|
+
model?: string;
|
|
184
|
+
speed?: number;
|
|
185
|
+
/**
|
|
186
|
+
* Free-text speaking-style instruction (tone, pace, emotion) forwarded to the
|
|
187
|
+
* TTS model. Only instruction-capable models honor it (OpenAI
|
|
188
|
+
* `gpt-4o-mini-tts`, Hume Octave, `qwen3-tts-instruct-flash`); the router
|
|
189
|
+
* drops it for any other resolved model, so it's safe to always pass.
|
|
190
|
+
*/
|
|
191
|
+
instructions?: string;
|
|
192
|
+
/**
|
|
193
|
+
* Normalize the text into spoken form before TTS — strip markdown/URLs, spell
|
|
194
|
+
* out numbers/currency/abbreviations. A deterministic safety net beneath the
|
|
195
|
+
* voice directive. The voice pipeline sets this; direct TTS callers default
|
|
196
|
+
* off and get literal text.
|
|
197
|
+
*/
|
|
198
|
+
spokenForm?: boolean;
|
|
199
|
+
constraints?: PipelineConstraints;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface SynthesizeResult {
|
|
203
|
+
/** Raw audio bytes. Format depends on the chosen provider — see `contentType`. */
|
|
204
|
+
audio: Uint8Array;
|
|
205
|
+
/** MIME type of the audio (e.g. "audio/mpeg" for ElevenLabs, "audio/pcm;rate=24000" for Cartesia). */
|
|
206
|
+
contentType: string;
|
|
207
|
+
provider: string;
|
|
208
|
+
model: string;
|
|
209
|
+
failoverCount: number;
|
|
210
|
+
scoresRunId: string | null;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface SynthesizeStreamResult extends AsyncIterable<Uint8Array> {
|
|
214
|
+
contentType: string;
|
|
215
|
+
provider: string;
|
|
216
|
+
model: string;
|
|
217
|
+
failoverCount: number;
|
|
218
|
+
scoresRunId: string | null;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// --- Voices (TTS catalog) ---------------------------------------------------
|
|
222
|
+
|
|
223
|
+
export interface VoiceCatalogEntry {
|
|
224
|
+
/** Routing-key vendor (matches `allowedProviders.tts` entries). */
|
|
225
|
+
vendor: string;
|
|
226
|
+
/** Voice id passed through to the provider's TTS API. */
|
|
227
|
+
id: string;
|
|
228
|
+
/** Human-readable label. */
|
|
229
|
+
name: string;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
export interface VoicesProviderEntry {
|
|
233
|
+
key: string;
|
|
234
|
+
name: string;
|
|
235
|
+
models: readonly string[];
|
|
236
|
+
/**
|
|
237
|
+
* `true` when the provider's voice library is account-scoped and must
|
|
238
|
+
* be fetched live from the provider (currently only ElevenLabs).
|
|
239
|
+
*/
|
|
240
|
+
voicesFetchedLive: boolean;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
export interface VoicesListResult {
|
|
244
|
+
voices: readonly VoiceCatalogEntry[];
|
|
245
|
+
providers: readonly VoicesProviderEntry[];
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
export interface VoicesListParams {
|
|
249
|
+
/**
|
|
250
|
+
* Filter to a single provider's voices. Accepts either the routing key
|
|
251
|
+
* (`cartesia`, `xai`, `alibaba`, `openai`, `inworld`, `elevenlabs`) or the
|
|
252
|
+
* catalog suffix form (`xai-tts`, `alibaba-tts`, `openai-tts`).
|
|
253
|
+
*/
|
|
254
|
+
provider?: string;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// --- Complete (LLM) ---------------------------------------------------------
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* One LLM-emitted tool invocation. `args` is a JSON-encoded string (LLMs may
|
|
261
|
+
* stream partial JSON; the proxy guarantees a complete, parseable string).
|
|
262
|
+
*/
|
|
263
|
+
export interface ChatToolCall {
|
|
264
|
+
id: string;
|
|
265
|
+
name: string;
|
|
266
|
+
args: string;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export interface ChatMessage {
|
|
270
|
+
role: 'system' | 'user' | 'assistant' | 'tool';
|
|
271
|
+
content: string;
|
|
272
|
+
/** Present on `role: 'assistant'` when the model invoked one or more tools. */
|
|
273
|
+
toolCalls?: ChatToolCall[];
|
|
274
|
+
/** Required on `role: 'tool'` — pairs with the `id` from a prior assistant `toolCalls[]`. */
|
|
275
|
+
toolCallId?: string;
|
|
276
|
+
/**
|
|
277
|
+
* Present on `role: 'tool'` when the customer's tool execute() threw or
|
|
278
|
+
* returned an error. The proxy translates to provider-native error signals
|
|
279
|
+
* (Anthropic `is_error: true`, OpenAI prefixed content) so the LLM sees the
|
|
280
|
+
* failure instead of treating the error message as a normal tool result.
|
|
281
|
+
*/
|
|
282
|
+
isError?: boolean;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Where the tool runs. `inline` (default) preserves the v0.3 behavior —
|
|
287
|
+
* the SDK / customer worker executes the tool. `webhook` opts into
|
|
288
|
+
* Speko's server-side execution: the proxy POSTs a Standard-Webhooks-
|
|
289
|
+
* signed request to your URL, folds the result back into the next
|
|
290
|
+
* provider turn, and only returns to you when the model emits final
|
|
291
|
+
* text or hands back an inline tool call. `builtin` runs Speko-managed
|
|
292
|
+
* primitives (e.g. `search_knowledge_base`, `transfer_call`, `end_call`).
|
|
293
|
+
* `integration` runs an
|
|
294
|
+
* org-installed Speko app action such as Google Calendar or Slack.
|
|
295
|
+
*/
|
|
296
|
+
export type ChatToolExecutionMode = 'inline' | 'webhook' | 'builtin' | 'integration';
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Spoken lead-in behavior before a server-executed tool runs. `auto` lets the
|
|
300
|
+
* gateway decide from the tool's recent execution durations; `always` forces a
|
|
301
|
+
* spoken lead-in (the gateway injects one when the model didn't produce any);
|
|
302
|
+
* `never` runs the tool silently.
|
|
303
|
+
*/
|
|
304
|
+
export type ChatToolPreToolSpeech = 'auto' | 'always' | 'never';
|
|
305
|
+
|
|
306
|
+
/**
|
|
307
|
+
* Source-of-execution config. Required when `executionMode` is
|
|
308
|
+
* `webhook`, `builtin`, or `integration`. Mirrors the SpekoTool `source` shape inside
|
|
309
|
+
* `@spekoai/tool-execution`.
|
|
310
|
+
*/
|
|
311
|
+
export type ChatToolSource =
|
|
312
|
+
| { kind: 'inline' }
|
|
313
|
+
| {
|
|
314
|
+
kind: 'webhook';
|
|
315
|
+
url: string;
|
|
316
|
+
/** Pointer into Speko's secrets store. Created via `POST /v1/agents/:id/tools` (which encrypts and stores the raw secret). */
|
|
317
|
+
secretRef: string;
|
|
318
|
+
headers?: Record<string, string>;
|
|
319
|
+
/**
|
|
320
|
+
* Outbound auth headers whose values are secret-referenced (resolved and
|
|
321
|
+
* injected by Speko at call time). The raw credential never leaves the
|
|
322
|
+
* server — only the `secretRef` pointer is exposed.
|
|
323
|
+
*/
|
|
324
|
+
authHeaders?: Array<{ name: string; secretRef: string }>;
|
|
325
|
+
timeoutMs?: number;
|
|
326
|
+
/** `async` returns `asyncAck` immediately while Speko dispatches the webhook in the background. */
|
|
327
|
+
responseMode?: 'sync' | 'async';
|
|
328
|
+
/** LLM-facing acknowledgement used when `responseMode` is `async`. */
|
|
329
|
+
asyncAck?: string;
|
|
330
|
+
}
|
|
331
|
+
| { kind: 'builtin'; name: string; config?: unknown }
|
|
332
|
+
| {
|
|
333
|
+
kind: 'integration';
|
|
334
|
+
installationId: string;
|
|
335
|
+
appKey: string;
|
|
336
|
+
actionKey: string;
|
|
337
|
+
config?: unknown;
|
|
338
|
+
};
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Tool definition exposed to the LLM. `parameters` is a JSON Schema (draft-7)
|
|
342
|
+
* object — typically generated from a Zod schema via
|
|
343
|
+
* `llm.toJsonSchema()` from `@livekit/agents`.
|
|
344
|
+
*
|
|
345
|
+
* `executionMode` and `source` are optional and back-compat: omitting
|
|
346
|
+
* both preserves the v0.3 inline behavior. Set `executionMode: 'webhook'`
|
|
347
|
+
* with a matching `source: { kind: 'webhook', ... }` or
|
|
348
|
+
* `source: { kind: 'integration', ... }` to opt into server-managed execution.
|
|
349
|
+
*/
|
|
350
|
+
export interface ChatTool {
|
|
351
|
+
name: string;
|
|
352
|
+
description: string;
|
|
353
|
+
parameters: Record<string, unknown>;
|
|
354
|
+
executionMode?: ChatToolExecutionMode;
|
|
355
|
+
source?: ChatToolSource;
|
|
356
|
+
/** Spoken lead-in behavior before this tool executes. Defaults to `auto` for registered tools. */
|
|
357
|
+
preToolSpeech?: ChatToolPreToolSpeech;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/** Mirrors LiveKit's `ToolChoice` for parity with the agents framework. */
|
|
361
|
+
export type ChatToolChoice =
|
|
362
|
+
| 'auto'
|
|
363
|
+
| 'none'
|
|
364
|
+
| 'required'
|
|
365
|
+
| { type: 'function'; function: { name: string } };
|
|
366
|
+
|
|
367
|
+
export type ReasoningEffort = 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
|
|
368
|
+
|
|
369
|
+
export interface CompleteParams {
|
|
370
|
+
messages: ChatMessage[];
|
|
371
|
+
intent: RoutingIntent;
|
|
372
|
+
/**
|
|
373
|
+
* Optional voice/session identifier forwarded as `x-session-id` for
|
|
374
|
+
* server-executed tools. The value is intentionally carried out-of-band
|
|
375
|
+
* so `/v1/complete` request bodies stay provider-shaped.
|
|
376
|
+
*/
|
|
377
|
+
sessionId?: string;
|
|
378
|
+
systemPrompt?: string;
|
|
379
|
+
temperature?: number;
|
|
380
|
+
maxTokens?: number;
|
|
381
|
+
reasoningEffort?: ReasoningEffort;
|
|
382
|
+
constraints?: PipelineConstraints;
|
|
383
|
+
tools?: ChatTool[];
|
|
384
|
+
toolChoice?: ChatToolChoice;
|
|
385
|
+
parallelToolCalls?: boolean;
|
|
386
|
+
/**
|
|
387
|
+
* Cap on how many provider hops the proxy may chain when one or more
|
|
388
|
+
* tools have `executionMode: 'webhook' | 'builtin'`. Each hop is one
|
|
389
|
+
* provider call. Default 8 server-side, hard cap 16. Ignored when all
|
|
390
|
+
* tools are inline (the proxy always returns toolCalls verbatim and
|
|
391
|
+
* the caller drives the loop themselves).
|
|
392
|
+
*/
|
|
393
|
+
maxToolHops?: number;
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export interface CompleteResult {
|
|
397
|
+
text: string;
|
|
398
|
+
provider: string;
|
|
399
|
+
model: string;
|
|
400
|
+
usage: {
|
|
401
|
+
promptTokens: number;
|
|
402
|
+
completionTokens: number;
|
|
403
|
+
};
|
|
404
|
+
failoverCount: number;
|
|
405
|
+
scoresRunId: string | null;
|
|
406
|
+
/** Present when the LLM invoked tools instead of (or in addition to) emitting text. */
|
|
407
|
+
toolCalls?: ChatToolCall[];
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
export type CompleteStreamEvent =
|
|
411
|
+
| {
|
|
412
|
+
type: 'meta';
|
|
413
|
+
provider: string;
|
|
414
|
+
model: string;
|
|
415
|
+
failoverCount: number;
|
|
416
|
+
totalFailoverCount: number;
|
|
417
|
+
scoresRunId: string | null;
|
|
418
|
+
hop: number;
|
|
419
|
+
}
|
|
420
|
+
| { type: 'delta'; text: string }
|
|
421
|
+
| (ChatToolCall & { type: 'tool_call' })
|
|
422
|
+
| {
|
|
423
|
+
type: 'server_tool_call';
|
|
424
|
+
id: string;
|
|
425
|
+
name: string;
|
|
426
|
+
status: 'started' | 'completed' | 'failed';
|
|
427
|
+
}
|
|
428
|
+
| (CompleteResult & { type: 'done' })
|
|
429
|
+
| { type: 'error'; error: string; code: string };
|
|
430
|
+
|
|
431
|
+
// --- Realtime (S2S) ---------------------------------------------------------
|
|
432
|
+
|
|
433
|
+
export type RealtimeProvider = 'openai' | 'google' | 'xai';
|
|
434
|
+
|
|
435
|
+
export interface RealtimeToolSpec {
|
|
436
|
+
name: string;
|
|
437
|
+
description: string;
|
|
438
|
+
parameters: Record<string, unknown>;
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
export interface RealtimeConnectParams {
|
|
442
|
+
/** Persisted agent whose workspace webhook routes should receive lifecycle events. */
|
|
443
|
+
agentId?: string;
|
|
444
|
+
provider: RealtimeProvider;
|
|
445
|
+
model: string;
|
|
446
|
+
voice?: string;
|
|
447
|
+
systemPrompt?: string;
|
|
448
|
+
temperature?: number;
|
|
449
|
+
inputSampleRate?: 16000 | 24000;
|
|
450
|
+
outputSampleRate?: 16000 | 24000;
|
|
451
|
+
tools?: RealtimeToolSpec[];
|
|
452
|
+
/** Exact-match attributes used only for workspace webhook routing. Requires agentId. */
|
|
453
|
+
webhookTags?: Record<string, string>;
|
|
454
|
+
metadata?: Record<string, unknown>;
|
|
455
|
+
/** Max session duration in seconds. Server-capped at 1800 (30 min). */
|
|
456
|
+
ttlSeconds?: number;
|
|
457
|
+
/** Reuse when retrying an ambiguous bootstrap timeout. Generated when omitted. */
|
|
458
|
+
idempotencyKey?: string;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Event shape emitted by a `RealtimeSessionHandle`. Binary audio comes in
|
|
463
|
+
* as `audio` frames; text control messages come through typed variants.
|
|
464
|
+
*/
|
|
465
|
+
export type RealtimeFrame =
|
|
466
|
+
| { type: 'ready'; inputSampleRate: 16000 | 24000; outputSampleRate: 16000 | 24000 }
|
|
467
|
+
| { type: 'audio'; pcm: Uint8Array; sampleRate: number }
|
|
468
|
+
| {
|
|
469
|
+
type: 'transcript';
|
|
470
|
+
role: 'user' | 'assistant';
|
|
471
|
+
text: string;
|
|
472
|
+
final: boolean;
|
|
473
|
+
}
|
|
474
|
+
| {
|
|
475
|
+
type: 'tool_call';
|
|
476
|
+
callId: string;
|
|
477
|
+
name: string;
|
|
478
|
+
arguments: string;
|
|
479
|
+
}
|
|
480
|
+
| {
|
|
481
|
+
type: 'usage';
|
|
482
|
+
inputAudioTokens: number;
|
|
483
|
+
outputAudioTokens: number;
|
|
484
|
+
}
|
|
485
|
+
| { type: 'interruption'; at: 'user' | 'assistant' }
|
|
486
|
+
| {
|
|
487
|
+
type: 'server_tool_call';
|
|
488
|
+
id: string;
|
|
489
|
+
name: string;
|
|
490
|
+
status: 'started' | 'completed' | 'failed';
|
|
491
|
+
}
|
|
492
|
+
| { type: 'error'; code: string; message: string }
|
|
493
|
+
| { type: 'close'; code: number; reason: string };
|
|
494
|
+
|
|
495
|
+
export type RealtimeEventHandler = (frame: RealtimeFrame) => void;
|
|
496
|
+
|
|
497
|
+
export interface RealtimeSessionHandle {
|
|
498
|
+
readonly sessionId: string;
|
|
499
|
+
readonly expiresAt: string;
|
|
500
|
+
readonly inputSampleRate: 16000 | 24000;
|
|
501
|
+
readonly outputSampleRate: 16000 | 24000;
|
|
502
|
+
|
|
503
|
+
/** Send a PCM16 audio chunk up to the model. */
|
|
504
|
+
sendAudio(pcm: Uint8Array): void;
|
|
505
|
+
|
|
506
|
+
/** Signal user-turn boundary / commit the input buffer. */
|
|
507
|
+
commit(): void;
|
|
508
|
+
|
|
509
|
+
/** Interrupt the current assistant response. */
|
|
510
|
+
interrupt(): void;
|
|
511
|
+
|
|
512
|
+
/** Return a previously-requested tool call result. */
|
|
513
|
+
sendToolResult(callId: string, output: string): void;
|
|
514
|
+
|
|
515
|
+
/** Subscribe to frames. Returns an unsubscribe callback. */
|
|
516
|
+
on(handler: RealtimeEventHandler): () => void;
|
|
517
|
+
|
|
518
|
+
/** Close the session. Safe to call multiple times. */
|
|
519
|
+
close(code?: number, reason?: string): void;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// ─── Voice (phone dial) ──────────────────────────────────────────────
|
|
523
|
+
|
|
524
|
+
export interface VoiceDialParams {
|
|
525
|
+
/** Destination number in E.164 format (e.g. "+12015551234"). */
|
|
526
|
+
to: string;
|
|
527
|
+
/** Caller ID. Falls back to the org default if omitted server-side. */
|
|
528
|
+
from?: string;
|
|
529
|
+
/** Persisted assistant to run for this call. When supplied, `intent` can be omitted. */
|
|
530
|
+
agentId?: string;
|
|
531
|
+
/** Routing intent — language is required, optimizeFor optional. */
|
|
532
|
+
intent?: RoutingIntent;
|
|
533
|
+
constraints?: PipelineConstraints;
|
|
534
|
+
/** TTS voice id passed through to the picked TTS provider. */
|
|
535
|
+
voice?: string;
|
|
536
|
+
/** Agent system prompt. */
|
|
537
|
+
systemPrompt?: string;
|
|
538
|
+
/** Optional first utterance. `null` is not accepted by phone dial; omit to use the agent default. */
|
|
539
|
+
firstMessage?: string;
|
|
540
|
+
/**
|
|
541
|
+
* Call-time values for template variables in `systemPrompt` / `firstMessage`.
|
|
542
|
+
* Sending this key (even `{}`) — or dialing with an agent that declares
|
|
543
|
+
* variables in its registry — compiles both strings as Liquid templates at
|
|
544
|
+
* call-create time: `{{name}}` interpolation, `{% if %}` / `{% elsif %}`
|
|
545
|
+
* branching, `| default:` filters, and platform-provided `system.*` values
|
|
546
|
+
* (`system.now`, `system.caller_number`, `system.call_id`, …).
|
|
547
|
+
*
|
|
548
|
+
* Resolution per variable: this map → the agent registry's default → inline
|
|
549
|
+
* `| default:` → the request fails with 400 `MISSING_TEMPLATE_VARIABLES`
|
|
550
|
+
* listing every unresolved name. Keys under `system.` are rejected. Omit
|
|
551
|
+
* this field entirely to send both strings verbatim (no compilation).
|
|
552
|
+
*
|
|
553
|
+
* @example
|
|
554
|
+
* ```ts
|
|
555
|
+
* await speko.voice.dial({
|
|
556
|
+
* to: '+12015551234',
|
|
557
|
+
* agentId: 'ag_123',
|
|
558
|
+
* systemPrompt:
|
|
559
|
+
* 'You are {{agent_name | default: "Ava"}} calling {{customer}}. ' +
|
|
560
|
+
* '{% if plan == "premium" %}Offer the priority upgrade.{% endif %} ' +
|
|
561
|
+
* 'The current time is {{system.now}}.',
|
|
562
|
+
* variables: { customer: 'Mr. Lee', plan: 'premium' },
|
|
563
|
+
* });
|
|
564
|
+
* ```
|
|
565
|
+
*/
|
|
566
|
+
variables?: Record<string, string>;
|
|
567
|
+
/**
|
|
568
|
+
* Per-call values for TOOLS ONLY — e.g. a short-lived access token scoped to
|
|
569
|
+
* the person being called, or a per-tenant API base URL. Unlike `variables`
|
|
570
|
+
* these never enter the system prompt, the transcript, or the model's
|
|
571
|
+
* context; they are stored encrypted and released only to tool execution.
|
|
572
|
+
* Custom-code tools read `session.secrets.<name>`; webhook tools may
|
|
573
|
+
* reference `{{name}}` in their `url` and `headers`. Names must be
|
|
574
|
+
* identifiers (`[A-Za-z_][A-Za-z0-9_]*`); up to 32 entries, 6 chars–4 KB each.
|
|
575
|
+
*
|
|
576
|
+
* @example
|
|
577
|
+
* ```ts
|
|
578
|
+
* await speko.voice.dial({
|
|
579
|
+
* to: '+12015551234',
|
|
580
|
+
* agentId: 'ag_123',
|
|
581
|
+
* toolSecrets: { base_url: 'https://acme.example.com', access_token: token },
|
|
582
|
+
* });
|
|
583
|
+
* ```
|
|
584
|
+
*/
|
|
585
|
+
toolSecrets?: Record<string, string>;
|
|
586
|
+
llm?: { temperature?: number; maxTokens?: number };
|
|
587
|
+
ttsOptions?: { sampleRate?: number; speed?: number };
|
|
588
|
+
sttOptions?: { keywords?: string[]; prompt?: string; language?: string };
|
|
589
|
+
/** Server-side wall-clock cap in seconds. Values are clamped server-side to 30s-4h. */
|
|
590
|
+
maxDurationSeconds?: number;
|
|
591
|
+
/**
|
|
592
|
+
* Optional per-call turn-taking overrides. `greetFirst` defaults ON for
|
|
593
|
+
* outbound (worker-side, 2026-07-03): the greeting plays immediately while
|
|
594
|
+
* AMD classifies in the background. Pass false to hold the greeting for the
|
|
595
|
+
* AMD verdict.
|
|
596
|
+
*/
|
|
597
|
+
turnHandling?: {
|
|
598
|
+
/** Local VAD for cascaded calls. Omit to use Silero. */
|
|
599
|
+
vad?: { provider: 'silero' | 'ai-coustics' };
|
|
600
|
+
/**
|
|
601
|
+
* Caller-leg input enhancement (ai-coustics). Omit for the platform default;
|
|
602
|
+
* `enabled: false` turns it off; `model` is plain Quail (default) or Quail Voice
|
|
603
|
+
* Focus (primary-speaker isolation, explicit opt-in).
|
|
604
|
+
*/
|
|
605
|
+
noiseCancellation?: { enabled: boolean; model?: 'quail' | 'quail-voice-focus' };
|
|
606
|
+
profile?: 'conversational' | 'ivr' | 'ivr_patient';
|
|
607
|
+
endpointing?: { minDelay?: number; maxDelay?: number };
|
|
608
|
+
interruption?: {
|
|
609
|
+
mode?: 'adaptive' | 'vad';
|
|
610
|
+
minDuration?: number;
|
|
611
|
+
minWords?: number;
|
|
612
|
+
};
|
|
613
|
+
turnDetection?: boolean | 'stt';
|
|
614
|
+
contextThreshold?: boolean;
|
|
615
|
+
greetFirst?: boolean;
|
|
616
|
+
/**
|
|
617
|
+
* Replaces the built-in prompt the answering-machine detector's classifier
|
|
618
|
+
* sees when deciding whether a human, an IVR menu or voicemail answered.
|
|
619
|
+
* Outbound only; max 2,000 characters.
|
|
620
|
+
*/
|
|
621
|
+
amdPrompt?: string;
|
|
622
|
+
/**
|
|
623
|
+
* What happens when native detection identifies recordable voicemail. `hangup` ends the call at the verdict; `leave_message` waits
|
|
624
|
+
* for the greeting to finish, speaks `voicemailMessage` once, then hangs
|
|
625
|
+
* up; `agent_decides` (default) hands the verdict to the LLM and lets the
|
|
626
|
+
* prompt's own voicemail rules act. Unavailable mailboxes always end without
|
|
627
|
+
* a message. Does not apply to menus/screeners or enable disabled/carrier AMD.
|
|
628
|
+
*/
|
|
629
|
+
onMachine?: 'hangup' | 'leave_message' | 'agent_decides';
|
|
630
|
+
/** Spoken once into the mailbox under `onMachine: 'leave_message'`. Renders the same `{{variables}}` as `firstMessage`. Max 2,000 characters. */
|
|
631
|
+
voicemailMessage?: string;
|
|
632
|
+
};
|
|
633
|
+
/** Optional per-call SIP routing hints. Carrier AMD requires trunk/provider support. */
|
|
634
|
+
telephony?: {
|
|
635
|
+
region?: string;
|
|
636
|
+
amd?: {
|
|
637
|
+
mode?: 'agent' | 'carrier' | 'disabled';
|
|
638
|
+
timeoutSeconds?: number;
|
|
639
|
+
};
|
|
640
|
+
};
|
|
641
|
+
/** Exact-match attributes used only for workspace webhook routing. Requires agentId. */
|
|
642
|
+
webhookTags?: Record<string, string>;
|
|
643
|
+
/** Free-form metadata round-tripped to your webhooks. */
|
|
644
|
+
metadata?: Record<string, unknown>;
|
|
645
|
+
/**
|
|
646
|
+
* @deprecated The agent-initiated end_call tool is now always on; the server
|
|
647
|
+
* accepts this field for compat but ignores it.
|
|
648
|
+
*/
|
|
649
|
+
endCall?: { enabled: boolean };
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
export interface VoiceDialResult {
|
|
653
|
+
sessionId: string;
|
|
654
|
+
callControlId: string;
|
|
655
|
+
roomName: string;
|
|
656
|
+
/** 'dialing' on a real call, 'dialing-stub' if managed telephony isn't configured. */
|
|
657
|
+
status: 'dialing' | 'dialing-stub';
|
|
658
|
+
to: string;
|
|
659
|
+
from: string;
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
// ─── Sessions ────────────────────────────────────────────────────────
|
|
663
|
+
|
|
664
|
+
/**
|
|
665
|
+
* One turn from `GET /v1/sessions/:id/transcript` — the lightweight live
|
|
666
|
+
* transcript poll. Note the camelCase keys: this endpoint's serialization
|
|
667
|
+
* differs from the snake_case `CallTranscriptEntry` embedded in `CallDetail`.
|
|
668
|
+
*/
|
|
669
|
+
export interface SessionTranscriptEntry {
|
|
670
|
+
id: string;
|
|
671
|
+
index: number;
|
|
672
|
+
source: 'user' | 'agent' | 'system';
|
|
673
|
+
text: string;
|
|
674
|
+
startedAt: string;
|
|
675
|
+
endedAt: string | null;
|
|
676
|
+
provider: string | null;
|
|
677
|
+
model: string | null;
|
|
678
|
+
/** Per-stage latency legs (ms) — null on user/system turns. */
|
|
679
|
+
eouMs: number | null;
|
|
680
|
+
llmTtftMs: number | null;
|
|
681
|
+
ttsTtfbMs: number | null;
|
|
682
|
+
latencyStatus: 'partial' | 'complete' | 'interrupted' | 'error' | null;
|
|
683
|
+
conversationalLatencyMs: number | null;
|
|
684
|
+
/** Tool calls the agent made on this turn (empty when none). */
|
|
685
|
+
toolCalls: { name: string; args: string }[];
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
export interface SessionTranscript {
|
|
689
|
+
entries: SessionTranscriptEntry[];
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
/**
|
|
693
|
+
* One push from `sessions.stream()` (SSE under the hood, auto-reconnecting).
|
|
694
|
+
* `end` is always the final event; transport-level reconnects and server
|
|
695
|
+
* stream rotations are handled inside the SDK and never surface here.
|
|
696
|
+
*/
|
|
697
|
+
export type SessionStreamEvent =
|
|
698
|
+
| { type: 'status'; status: string; endedAt: string | null }
|
|
699
|
+
| { type: 'transcript'; turn: SessionTranscriptEntry }
|
|
700
|
+
| { type: 'event'; event: CallEvent }
|
|
701
|
+
| { type: 'end'; reason: 'session_ended' };
|
|
702
|
+
|
|
703
|
+
export interface SessionStreamOptions {
|
|
704
|
+
/**
|
|
705
|
+
* Resume position (`"<lastTurnIndex>:<lastEventCreatedAtMs>"`). Rarely
|
|
706
|
+
* needed — the iterator tracks it internally across reconnects; pass it
|
|
707
|
+
* only to resume a NEW iterator after your own process restarted.
|
|
708
|
+
*/
|
|
709
|
+
cursor?: string;
|
|
710
|
+
/** Abort to stop streaming (the iterator returns). */
|
|
711
|
+
signal?: AbortSignal;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
// ─── Phone numbers ───────────────────────────────────────────────────
|
|
715
|
+
|
|
716
|
+
export type PhoneNumberDirection = 'inbound' | 'outbound' | 'both';
|
|
717
|
+
export type PhoneNumberSource = 'managed' | 'sip_trunk';
|
|
718
|
+
export type PhoneNumberSmsAssignmentStatus =
|
|
719
|
+
| 'FAILED_ASSIGNMENT'
|
|
720
|
+
| 'PENDING_ASSIGNMENT'
|
|
721
|
+
| 'ASSIGNED'
|
|
722
|
+
| 'PENDING_UNASSIGNMENT'
|
|
723
|
+
| 'FAILED_UNASSIGNMENT';
|
|
724
|
+
|
|
725
|
+
export interface PhoneNumberSetupStatus {
|
|
726
|
+
status: 'ready' | 'action_required' | 'suspended';
|
|
727
|
+
inboundReady: boolean;
|
|
728
|
+
outboundReady: boolean;
|
|
729
|
+
agentReady: boolean;
|
|
730
|
+
forwardingRequired: boolean;
|
|
731
|
+
sipConnectionReady: boolean;
|
|
732
|
+
issues: string[];
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
export interface PhoneNumberRow {
|
|
736
|
+
id: string;
|
|
737
|
+
organizationId: string;
|
|
738
|
+
e164: string;
|
|
739
|
+
source: PhoneNumberSource;
|
|
740
|
+
/** Platform-neutral resource id for a platform-managed number. */
|
|
741
|
+
providerResourceId: string | null;
|
|
742
|
+
/** @deprecated Use `providerResourceId`. */
|
|
743
|
+
telnyxPhoneNumberId: string | null;
|
|
744
|
+
/** @deprecated LiveKit trunk IDs are internal and no longer exposed. */
|
|
745
|
+
sipTrunkId: string | null;
|
|
746
|
+
sipConnectionInstallationId: string | null;
|
|
747
|
+
sipProviderName: string | null;
|
|
748
|
+
direction: PhoneNumberDirection;
|
|
749
|
+
dispatchMetadataTemplate: Record<string, unknown> | null;
|
|
750
|
+
label: string | null;
|
|
751
|
+
sms10dlcProfileId: string | null;
|
|
752
|
+
smsCampaignId: string | null;
|
|
753
|
+
smsAssignmentStatus: PhoneNumberSmsAssignmentStatus | null;
|
|
754
|
+
smsAssignmentUpdatedAt: string | null;
|
|
755
|
+
telnyxMessagingProfileId: string | null;
|
|
756
|
+
smsMessagingProfileStatus: 'pending' | 'ready' | 'failed';
|
|
757
|
+
smsMessagingProfileUpdatedAt: string | null;
|
|
758
|
+
smsMessagingProfileError: string | null;
|
|
759
|
+
smsAutomationEnabled: boolean;
|
|
760
|
+
/**
|
|
761
|
+
* 1:1 link to a persisted agent. When set, inbound calls hydrate
|
|
762
|
+
* pipeline config from the agent row instead of (or alongside) the
|
|
763
|
+
* dispatch_metadata_template.
|
|
764
|
+
*/
|
|
765
|
+
agentId: string | null;
|
|
766
|
+
/**
|
|
767
|
+
* Inbound destination when this number answers to a HUMAN rather than an
|
|
768
|
+
* agent — the org-defined broker whose softphone is rung. Mutually
|
|
769
|
+
* exclusive with `agentId`: assigning one clears the other, because a number
|
|
770
|
+
* routed to a broker is provisioned so that no agent joins ahead of them.
|
|
771
|
+
*/
|
|
772
|
+
routeToBrokerId: string | null;
|
|
773
|
+
setupStatus: PhoneNumberSetupStatus;
|
|
774
|
+
nextChargeAt: string;
|
|
775
|
+
lastChargedAt: string | null;
|
|
776
|
+
/** Effective billing-or-compliance suspension timestamp. */
|
|
777
|
+
suspendedAt: string | null;
|
|
778
|
+
/** Billing-only suspension, retained independently from compliance review. */
|
|
779
|
+
billingSuspendedAt?: string | null;
|
|
780
|
+
/** Compliance-only suspension for Speko-managed numbers. */
|
|
781
|
+
complianceSuspendedAt?: string | null;
|
|
782
|
+
suspensionReason?: 'billing' | 'compliance' | null;
|
|
783
|
+
createdAt: string;
|
|
784
|
+
updatedAt: string;
|
|
785
|
+
}
|
|
786
|
+
|
|
787
|
+
export interface PhoneNumberCreateParams {
|
|
788
|
+
e164: string;
|
|
789
|
+
direction?: PhoneNumberDirection;
|
|
790
|
+
/** Dispatch metadata template (variables `{{var}}` resolved at dial). */
|
|
791
|
+
dispatchMetadataTemplate?: Record<string, unknown>;
|
|
792
|
+
label?: string;
|
|
793
|
+
/** 1:1 link to an agent in the same org. */
|
|
794
|
+
agentId?: string;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
export type PhoneNumberImportSipTrunkParams = {
|
|
798
|
+
e164: string;
|
|
799
|
+
/** Optional provider/account label for display. */
|
|
800
|
+
sipProviderName?: string;
|
|
801
|
+
direction?: PhoneNumberDirection;
|
|
802
|
+
/** Dispatch metadata template (variables `{{var}}` resolved at dial). */
|
|
803
|
+
dispatchMetadataTemplate?: Record<string, unknown>;
|
|
804
|
+
label?: string;
|
|
805
|
+
/** 1:1 link to an agent in the same org. */
|
|
806
|
+
agentId?: string;
|
|
807
|
+
} & (
|
|
808
|
+
| {
|
|
809
|
+
/** Installed SIP connection integration id. Preferred for productized SIP connections. */
|
|
810
|
+
sipConnectionInstallationId: string;
|
|
811
|
+
/** Legacy LiveKit outbound trunk id. Ignored when `sipConnectionInstallationId` is present. */
|
|
812
|
+
sipTrunkId?: string;
|
|
813
|
+
}
|
|
814
|
+
| {
|
|
815
|
+
/** Legacy LiveKit outbound trunk id. Use `sipConnectionInstallationId` for new integrations. */
|
|
816
|
+
sipTrunkId: string;
|
|
817
|
+
sipConnectionInstallationId?: string;
|
|
818
|
+
}
|
|
819
|
+
);
|
|
820
|
+
|
|
821
|
+
export interface PhoneNumberUpdateParams {
|
|
822
|
+
direction?: PhoneNumberDirection;
|
|
823
|
+
dispatchMetadataTemplate?: Record<string, unknown> | null;
|
|
824
|
+
label?: string | null;
|
|
825
|
+
/** Pass `null` to unlink, a string to relink. */
|
|
826
|
+
agentId?: string | null;
|
|
827
|
+
/**
|
|
828
|
+
* Route inbound calls on this number to a human broker's softphone instead of
|
|
829
|
+
* an agent — pass your org-defined broker id, or `null` to stop. Setting
|
|
830
|
+
* it clears `agentId`, and setting `agentId` clears it; sending both in one
|
|
831
|
+
* request is a validation error. Requires the human-calling feature.
|
|
832
|
+
*/
|
|
833
|
+
routeToBrokerId?: string | null;
|
|
834
|
+
/** Owner/admin-only opt-in for inbound SMS agent replies on this number. */
|
|
835
|
+
smsAutomationEnabled?: boolean;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
export interface AvailablePhoneNumber {
|
|
839
|
+
e164: string;
|
|
840
|
+
friendlyName: string;
|
|
841
|
+
monthlyCostUsd: number;
|
|
842
|
+
upfrontCostUsd: number;
|
|
843
|
+
features: string[];
|
|
844
|
+
region: {
|
|
845
|
+
state: string | null;
|
|
846
|
+
locality: string | null;
|
|
847
|
+
rateCenter: string | null;
|
|
848
|
+
};
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
export interface PhoneNumberSearchParams {
|
|
852
|
+
/** 3-digit US area code, e.g. "415". */
|
|
853
|
+
areaCode?: string;
|
|
854
|
+
/** Optional locality filter, e.g. "San Francisco". */
|
|
855
|
+
locality?: string;
|
|
856
|
+
/** Max results. Default 10. */
|
|
857
|
+
limit?: number;
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
export type PhoneNumberKybStatus =
|
|
861
|
+
| 'missing'
|
|
862
|
+
| 'draft'
|
|
863
|
+
| 'submitted'
|
|
864
|
+
| 'approved'
|
|
865
|
+
| 'rejected'
|
|
866
|
+
| 'revoked';
|
|
867
|
+
|
|
868
|
+
export type PhoneNumberKybSubmissionStatus = Exclude<PhoneNumberKybStatus, 'missing'>;
|
|
869
|
+
|
|
870
|
+
export type PhoneNumberKybSlackNotificationStatus = 'not_queued' | 'queued' | 'enqueue_failed';
|
|
871
|
+
|
|
872
|
+
export interface PhoneNumberKybBusinessProfile {
|
|
873
|
+
legalName: string;
|
|
874
|
+
displayName: string;
|
|
875
|
+
entityType: string;
|
|
876
|
+
country: string;
|
|
877
|
+
registrationId?: string;
|
|
878
|
+
website: string;
|
|
879
|
+
address: {
|
|
880
|
+
street: string;
|
|
881
|
+
city: string;
|
|
882
|
+
state: string;
|
|
883
|
+
postalCode: string;
|
|
884
|
+
country: string;
|
|
885
|
+
};
|
|
886
|
+
useCase: string;
|
|
887
|
+
expectedUsage: string;
|
|
888
|
+
}
|
|
889
|
+
|
|
890
|
+
export interface PhoneNumberKybAuthorizedRepresentative {
|
|
891
|
+
name: string;
|
|
892
|
+
title: string;
|
|
893
|
+
email: string;
|
|
894
|
+
phone?: string;
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
export interface PhoneNumberKybDeclaration {
|
|
898
|
+
businessName: string;
|
|
899
|
+
useCase: string;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
export type PhoneNumberKybAttestor =
|
|
903
|
+
| {
|
|
904
|
+
kind: 'user';
|
|
905
|
+
userId: string;
|
|
906
|
+
name: string;
|
|
907
|
+
email: string;
|
|
908
|
+
organizationRole: string | null;
|
|
909
|
+
}
|
|
910
|
+
| { kind: 'api_key'; apiKeyId: string };
|
|
911
|
+
|
|
912
|
+
export interface PhoneNumberKybAttestationContract {
|
|
913
|
+
version: string;
|
|
914
|
+
text: string;
|
|
915
|
+
termsVersion: string;
|
|
916
|
+
termsUrl: string;
|
|
917
|
+
}
|
|
918
|
+
|
|
919
|
+
export interface PhoneNumberKybDraftParams {
|
|
920
|
+
businessProfile: PhoneNumberKybBusinessProfile;
|
|
921
|
+
authorizedRepresentative: PhoneNumberKybAuthorizedRepresentative;
|
|
922
|
+
attestationAccepted?: boolean;
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
export type PhoneNumberKybSubmitParams =
|
|
926
|
+
| {
|
|
927
|
+
declaration: PhoneNumberKybDeclaration;
|
|
928
|
+
attestationAccepted: true;
|
|
929
|
+
attestationVersion: string;
|
|
930
|
+
}
|
|
931
|
+
| {
|
|
932
|
+
businessProfile: PhoneNumberKybBusinessProfile;
|
|
933
|
+
authorizedRepresentative: PhoneNumberKybAuthorizedRepresentative;
|
|
934
|
+
attestationAccepted: true;
|
|
935
|
+
attestationVersion?: string;
|
|
936
|
+
};
|
|
937
|
+
|
|
938
|
+
export interface PhoneNumberKybSubmission {
|
|
939
|
+
id: string;
|
|
940
|
+
organizationId: string;
|
|
941
|
+
status: PhoneNumberKybSubmissionStatus;
|
|
942
|
+
businessProfile: PhoneNumberKybBusinessProfile | null;
|
|
943
|
+
authorizedRepresentative: PhoneNumberKybAuthorizedRepresentative | null;
|
|
944
|
+
declaration?: PhoneNumberKybDeclaration | null;
|
|
945
|
+
attestor?: PhoneNumberKybAttestor | null;
|
|
946
|
+
attestationAccepted: boolean;
|
|
947
|
+
attestationVersion?: string | null;
|
|
948
|
+
attestationText?: string | null;
|
|
949
|
+
termsVersion?: string | null;
|
|
950
|
+
attestedAt: string | null;
|
|
951
|
+
accessHoldAt?: string | null;
|
|
952
|
+
accessHoldReason?: 'rejected' | 'revoked' | null;
|
|
953
|
+
submittedByUserId: string | null;
|
|
954
|
+
submittedByEmail: string | null;
|
|
955
|
+
submittedByApiKeyId: string | null;
|
|
956
|
+
submittedAt: string | null;
|
|
957
|
+
reviewerUserId: string | null;
|
|
958
|
+
reviewerEmail: string | null;
|
|
959
|
+
reviewedAt: string | null;
|
|
960
|
+
rejectionReason: string | null;
|
|
961
|
+
slackNotificationStatus: PhoneNumberKybSlackNotificationStatus;
|
|
962
|
+
slackNotificationJobId: string | null;
|
|
963
|
+
slackNotificationError: string | null;
|
|
964
|
+
createdAt: string;
|
|
965
|
+
updatedAt: string;
|
|
966
|
+
}
|
|
967
|
+
|
|
968
|
+
export interface PhoneNumberKybOverview {
|
|
969
|
+
status: PhoneNumberKybStatus;
|
|
970
|
+
submission: PhoneNumberKybSubmission | null;
|
|
971
|
+
declarationPrefill?: PhoneNumberKybDeclaration;
|
|
972
|
+
requiredAttestation?: PhoneNumberKybAttestationContract;
|
|
973
|
+
attestationRequired?: boolean;
|
|
974
|
+
complianceAccess?: 'enabled' | 'awaiting_attestation' | 'suspended';
|
|
975
|
+
prefill: {
|
|
976
|
+
businessProfile: PhoneNumberKybBusinessProfile;
|
|
977
|
+
authorizedRepresentative: PhoneNumberKybAuthorizedRepresentative;
|
|
978
|
+
} | null;
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
// ─── Agents ──────────────────────────────────────────────────────────
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* Routing intent for an agent's voice pipeline. Narrower than the
|
|
985
|
+
* top-level {@link RoutingIntent} — the agents API specifically
|
|
986
|
+
* accepts `latency`, `quality`, or `cost` (no `balanced` / `accuracy`).
|
|
987
|
+
*/
|
|
988
|
+
export interface AgentIntent {
|
|
989
|
+
/** BCP-47 language tag, e.g. "en" or "es-MX". */
|
|
990
|
+
language: string;
|
|
991
|
+
optimizeFor?: 'latency' | 'quality' | 'cost';
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
export interface AgentLlmOptions {
|
|
995
|
+
temperature?: number;
|
|
996
|
+
maxTokens?: number;
|
|
997
|
+
model?: string;
|
|
998
|
+
}
|
|
999
|
+
|
|
1000
|
+
export interface AgentStackPreferences {
|
|
1001
|
+
allowedProviders?: {
|
|
1002
|
+
stt?: string[];
|
|
1003
|
+
llm?: string[];
|
|
1004
|
+
tts?: string[];
|
|
1005
|
+
s2s?: string[];
|
|
1006
|
+
};
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
export interface AgentSttOptions {
|
|
1010
|
+
/** Vocabulary keywords forwarded to whichever STT provider the router picks. */
|
|
1011
|
+
keywords?: string[];
|
|
1012
|
+
/**
|
|
1013
|
+
* Free-text transcription context (domain, names, expected phrases), max
|
|
1014
|
+
* 2000 chars. Honored only by prompt-capable STT models (OpenAI
|
|
1015
|
+
* gpt-4o-transcribe family, AssemblyAI Universal-3 Pro tiers).
|
|
1016
|
+
*/
|
|
1017
|
+
prompt?: string;
|
|
1018
|
+
/**
|
|
1019
|
+
* STT stream-language override. A BCP-47-ish tag ('en', 'es-MX'), a
|
|
1020
|
+
* provider keyword like Deepgram's 'multi', or 'auto' to let the provider
|
|
1021
|
+
* detect the spoken language itself (Soniox auto-detects when hints are
|
|
1022
|
+
* omitted). Never affects stack routing — that keeps the agent language.
|
|
1023
|
+
*/
|
|
1024
|
+
language?: string;
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/**
|
|
1028
|
+
* Built-in ambience clip ids supported by the hosted worker. Custom clip
|
|
1029
|
+
* uploads are intentionally not yet supported — pinning to the built-ins
|
|
1030
|
+
* keeps the v1 API simple and lets the worker map straight to the
|
|
1031
|
+
* `BuiltinAudioClip` enum.
|
|
1032
|
+
*/
|
|
1033
|
+
export type AgentAmbientClip =
|
|
1034
|
+
| 'office-ambience'
|
|
1035
|
+
| 'city-ambience'
|
|
1036
|
+
| 'forest-ambience'
|
|
1037
|
+
| 'crowded-room'
|
|
1038
|
+
| 'keyboard-typing'
|
|
1039
|
+
| 'keyboard-typing2';
|
|
1040
|
+
|
|
1041
|
+
/**
|
|
1042
|
+
* Per-agent background audio. Today only ambient (continuous loop) is
|
|
1043
|
+
* supported. The ambience plays on a separate media track mixed
|
|
1044
|
+
* server-side, so it reaches both browser (WebRTC) and phone (SIP) callers
|
|
1045
|
+
* without any client-side change.
|
|
1046
|
+
*/
|
|
1047
|
+
export interface AgentBackgroundAudio {
|
|
1048
|
+
ambient?: {
|
|
1049
|
+
clip: AgentAmbientClip;
|
|
1050
|
+
/**
|
|
1051
|
+
* Linear gain in `[0, 16]`, defaulting to 1.0 — the clip's own recorded
|
|
1052
|
+
* level, which is not the same as "full volume". The built-in clips are
|
|
1053
|
+
* mastered roughly 30 dB apart, so the useful range differs per clip:
|
|
1054
|
+
* `office-ambience` is very quiet (about -52 LUFS) and needs ~5-10 to sit
|
|
1055
|
+
* audibly under speech, `city-ambience` is about right at 1, and
|
|
1056
|
+
* `crowded-room` is loud enough that it distorts past ~1.6.
|
|
1057
|
+
*/
|
|
1058
|
+
volume?: number;
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
|
|
1062
|
+
export interface AgentSpeechNormalization {
|
|
1063
|
+
pronunciationDictionary?: Record<string, string>;
|
|
1064
|
+
textReplacements?: Record<string, string>;
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
/**
|
|
1068
|
+
* A caller-defined post-call extraction field. Only meaningful on the
|
|
1069
|
+
* `postCall` webhook: the call-analysis pass fills each from the transcript per
|
|
1070
|
+
* `description`, typed by `type`, and the values are delivered under the
|
|
1071
|
+
* webhook payload's top-level `custom_data` object keyed by `name`. `options`
|
|
1072
|
+
* is required for `enum` fields.
|
|
1073
|
+
*/
|
|
1074
|
+
export interface AgentExtractionField {
|
|
1075
|
+
/**
|
|
1076
|
+
* Stable key the value lands under in `custom_data`. Must be a valid
|
|
1077
|
+
* identifier (`^[a-zA-Z_][a-zA-Z0-9_]*$`), up to 64 chars, unique per webhook.
|
|
1078
|
+
*/
|
|
1079
|
+
name: string;
|
|
1080
|
+
type: 'string' | 'number' | 'boolean' | 'enum';
|
|
1081
|
+
/**
|
|
1082
|
+
* Instruction the LLM uses to extract this field. 1 to 10,000 characters,
|
|
1083
|
+
* and at most 40,000 characters combined across all fields on the webhook.
|
|
1084
|
+
*/
|
|
1085
|
+
description: string;
|
|
1086
|
+
/**
|
|
1087
|
+
* Allowed values — required (and only valid) when `type` is `'enum'`.
|
|
1088
|
+
* 1–50 options, each up to 120 characters.
|
|
1089
|
+
*/
|
|
1090
|
+
options?: string[];
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
/**
|
|
1094
|
+
* Outbound auth header input — `value` is the plaintext credential Speko
|
|
1095
|
+
* encrypts at rest. Required on create; omit on update to keep the value
|
|
1096
|
+
* already stored under this header's ref.
|
|
1097
|
+
*/
|
|
1098
|
+
export interface AgentWebhookAuthHeaderInput {
|
|
1099
|
+
name: string;
|
|
1100
|
+
value?: string;
|
|
1101
|
+
}
|
|
1102
|
+
|
|
1103
|
+
/** Outbound auth header as returned by the API — value stays server-side. */
|
|
1104
|
+
export interface AgentWebhookAuthHeader {
|
|
1105
|
+
name: string;
|
|
1106
|
+
secretRef: string;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
export interface AgentLifecycleWebhookCreate {
|
|
1110
|
+
url: string;
|
|
1111
|
+
/**
|
|
1112
|
+
* Optional per-webhook signing secret. When supplied, this endpoint signs
|
|
1113
|
+
* with its own secret instead of the shared org-level secret from API keys.
|
|
1114
|
+
*/
|
|
1115
|
+
secret?: string;
|
|
1116
|
+
headers?: Record<string, string>;
|
|
1117
|
+
/** Secret-referenced outbound auth headers (e.g. a Bearer token your endpoint requires). */
|
|
1118
|
+
authHeaders?: AgentWebhookAuthHeaderInput[];
|
|
1119
|
+
timeoutMs?: number;
|
|
1120
|
+
responseMode?: 'sync' | 'async';
|
|
1121
|
+
asyncAck?: string;
|
|
1122
|
+
/** Post-call data-extraction fields. Applies to the `postCall` webhook only. */
|
|
1123
|
+
extractionFields?: AgentExtractionField[];
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
export interface AgentLifecycleWebhookUpdate {
|
|
1127
|
+
url: string;
|
|
1128
|
+
/**
|
|
1129
|
+
* Optional per-webhook signing secret. Supply to set/rotate a per-webhook
|
|
1130
|
+
* secret; omit to keep the existing (or shared org-level) secret.
|
|
1131
|
+
*/
|
|
1132
|
+
secret?: string;
|
|
1133
|
+
headers?: Record<string, string>;
|
|
1134
|
+
/** Secret-referenced outbound auth headers. Replaces the stored set; omit a `value` to keep it. */
|
|
1135
|
+
authHeaders?: AgentWebhookAuthHeaderInput[];
|
|
1136
|
+
timeoutMs?: number;
|
|
1137
|
+
responseMode?: 'sync' | 'async';
|
|
1138
|
+
asyncAck?: string;
|
|
1139
|
+
/** Post-call data-extraction fields. Applies to the `postCall` webhook only. */
|
|
1140
|
+
extractionFields?: AgentExtractionField[];
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
export interface AgentLifecycleWebhookSerialized {
|
|
1144
|
+
url: string;
|
|
1145
|
+
secretRef: string;
|
|
1146
|
+
headers?: Record<string, string>;
|
|
1147
|
+
/** Outbound auth-header pointers; values stay encrypted server-side. */
|
|
1148
|
+
authHeaders?: AgentWebhookAuthHeader[];
|
|
1149
|
+
timeoutMs?: number;
|
|
1150
|
+
responseMode?: 'sync' | 'async';
|
|
1151
|
+
asyncAck?: string;
|
|
1152
|
+
/** Post-call data-extraction fields. Present on the `postCall` webhook only. */
|
|
1153
|
+
extractionFields?: AgentExtractionField[];
|
|
1154
|
+
}
|
|
1155
|
+
|
|
1156
|
+
export interface AgentWebhooksSerialized {
|
|
1157
|
+
preCall?: AgentLifecycleWebhookSerialized;
|
|
1158
|
+
postCall?: AgentLifecycleWebhookSerialized;
|
|
1159
|
+
status?: AgentLifecycleWebhookSerialized;
|
|
1160
|
+
/** Dedicated `call.analysis` webhook — LLM analysis results only. */
|
|
1161
|
+
analysis?: AgentLifecycleWebhookSerialized;
|
|
1162
|
+
/** Dedicated `call.recording` webhook — fires when the recording turns terminal. */
|
|
1163
|
+
recording?: AgentLifecycleWebhookSerialized;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
1166
|
+
export interface AgentWebhooksCreate {
|
|
1167
|
+
preCall?: AgentLifecycleWebhookCreate;
|
|
1168
|
+
postCall?: AgentLifecycleWebhookCreate;
|
|
1169
|
+
status?: AgentLifecycleWebhookCreate;
|
|
1170
|
+
/**
|
|
1171
|
+
* Dedicated `call.analysis` webhook. Delivered once per call when the LLM
|
|
1172
|
+
* analysis completes: summary, outcome, structured_data, and custom_data —
|
|
1173
|
+
* without the transcript/cost/recording of the combined `call.report`.
|
|
1174
|
+
*/
|
|
1175
|
+
analysis?: AgentLifecycleWebhookCreate;
|
|
1176
|
+
/**
|
|
1177
|
+
* Dedicated `call.recording` webhook. Delivered once per call when the
|
|
1178
|
+
* recording reaches a terminal state — `ready` carries the presigned
|
|
1179
|
+
* `recording_url` (7-day TTL), `failed` carries `recording_url: null`.
|
|
1180
|
+
*/
|
|
1181
|
+
recording?: AgentLifecycleWebhookCreate;
|
|
1182
|
+
}
|
|
1183
|
+
|
|
1184
|
+
export interface AgentWebhooksUpdate {
|
|
1185
|
+
preCall?: AgentLifecycleWebhookUpdate | null;
|
|
1186
|
+
postCall?: AgentLifecycleWebhookUpdate | null;
|
|
1187
|
+
status?: AgentLifecycleWebhookUpdate | null;
|
|
1188
|
+
analysis?: AgentLifecycleWebhookUpdate | null;
|
|
1189
|
+
recording?: AgentLifecycleWebhookUpdate | null;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
// ─── Workspace webhooks ─────────────────────────────────────────────
|
|
1193
|
+
|
|
1194
|
+
/**
|
|
1195
|
+
* Everything a workspace webhook endpoint can subscribe to.
|
|
1196
|
+
*
|
|
1197
|
+
* Two families, and they behave differently on the wire:
|
|
1198
|
+
*
|
|
1199
|
+
* **AI voice-session events** (`call.pre_call` … `call.recording`) describe one
|
|
1200
|
+
* `voice_session` as it progresses, and carry a `session_id`.
|
|
1201
|
+
*
|
|
1202
|
+
* **Programmable-voice control events** (`call.initiated` … `call.hangup`) are
|
|
1203
|
+
* the webhook projection of the human-calling event stream — the same events
|
|
1204
|
+
* {@link CallControl.events} returns. A human call is not a `voice_session`, so
|
|
1205
|
+
* there is no session id to correlate on: the payload carries `call_id`,
|
|
1206
|
+
* `control_id` (null for call-scoped events that belong to no single leg),
|
|
1207
|
+
* `event_id` and `occurred_at`, merged with the event's own payload, and
|
|
1208
|
+
* `call_id` is the correlation key.
|
|
1209
|
+
*
|
|
1210
|
+
* Control events are delivered **once, without automatic retry**. Only
|
|
1211
|
+
* `call.report`, `call.analysis` and `call.recording` are durable — for those, a
|
|
1212
|
+
* failed delivery is re-attempted on a backoff. A control event that misses its
|
|
1213
|
+
* endpoint is gone from the webhook feed; the call's own event history
|
|
1214
|
+
* ({@link CallControl.events}) is the durable record, so reconcile from there
|
|
1215
|
+
* rather than treating the webhook as a queue.
|
|
1216
|
+
*/
|
|
1217
|
+
export type WorkspaceWebhookEventType =
|
|
1218
|
+
| 'call.pre_call'
|
|
1219
|
+
| 'call.status'
|
|
1220
|
+
| 'call.report'
|
|
1221
|
+
| 'call.analysis'
|
|
1222
|
+
| 'call.recording'
|
|
1223
|
+
| 'call.initiated'
|
|
1224
|
+
| 'call.ringing'
|
|
1225
|
+
| 'call.answered'
|
|
1226
|
+
| 'call.bridged'
|
|
1227
|
+
| 'call.hold'
|
|
1228
|
+
| 'call.unhold'
|
|
1229
|
+
| 'call.mute'
|
|
1230
|
+
| 'call.unmute'
|
|
1231
|
+
// No `call.dtmf.received`: an inbound keypress reaches the platform as an
|
|
1232
|
+
// in-room data packet addressed to room participants, never to the webhook
|
|
1233
|
+
// receiver, so there is no server-side producer to subscribe to. Read it off
|
|
1234
|
+
// the room's data channel in the browser instead.
|
|
1235
|
+
| 'call.dtmf.sent'
|
|
1236
|
+
| 'call.transfer.initiated'
|
|
1237
|
+
| 'call.transfer.completed'
|
|
1238
|
+
| 'call.transfer.failed'
|
|
1239
|
+
| 'call.leg.hangup'
|
|
1240
|
+
| 'call.hangup'
|
|
1241
|
+
| 'sms.received'
|
|
1242
|
+
| 'sms.accepted'
|
|
1243
|
+
| 'sms.sent'
|
|
1244
|
+
| 'sms.delivered'
|
|
1245
|
+
| 'sms.delivery_failed'
|
|
1246
|
+
| 'sms.submission_unknown'
|
|
1247
|
+
| 'sms.opted_out'
|
|
1248
|
+
| 'sms.opted_in';
|
|
1249
|
+
|
|
1250
|
+
export type WebhookEventType =
|
|
1251
|
+
| WorkspaceWebhookEventType
|
|
1252
|
+
| 'imessage.received'
|
|
1253
|
+
| 'imessage.reaction_received'
|
|
1254
|
+
| 'imessage.sent'
|
|
1255
|
+
| 'imessage.delivered'
|
|
1256
|
+
| 'imessage.delivery_failed';
|
|
1257
|
+
|
|
1258
|
+
export type WebhookDeliveryStatus =
|
|
1259
|
+
| 'pending'
|
|
1260
|
+
| 'delivering'
|
|
1261
|
+
| 'succeeded'
|
|
1262
|
+
| 'failed'
|
|
1263
|
+
| 'cancelled'
|
|
1264
|
+
| 'expired';
|
|
1265
|
+
|
|
1266
|
+
export interface WebhookEndpointAuthHeaderInput {
|
|
1267
|
+
name: string;
|
|
1268
|
+
/** Write-only plaintext. The server encrypts it and never returns it. */
|
|
1269
|
+
value: string;
|
|
1270
|
+
}
|
|
1271
|
+
|
|
1272
|
+
export interface WebhookEndpointAuthHeaderUpdate {
|
|
1273
|
+
name: string;
|
|
1274
|
+
/** Supply to set or rotate; omit to retain the stored value for this header name. */
|
|
1275
|
+
value?: string;
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
export interface WebhookEndpointInput {
|
|
1279
|
+
name: string;
|
|
1280
|
+
url: string;
|
|
1281
|
+
events: WorkspaceWebhookEventType[];
|
|
1282
|
+
/** Defaults to true. When false, agentIds must contain at least one agent. */
|
|
1283
|
+
allAgents?: boolean;
|
|
1284
|
+
agentIds?: string[];
|
|
1285
|
+
filterTags?: Record<string, string>;
|
|
1286
|
+
headers?: Record<string, string>;
|
|
1287
|
+
authHeaders?: WebhookEndpointAuthHeaderInput[];
|
|
1288
|
+
timeoutMs?: number;
|
|
1289
|
+
signingSecretSource?: 'workspace' | 'custom';
|
|
1290
|
+
/** Write-only. Required when signingSecretSource is custom. */
|
|
1291
|
+
signingSecret?: string;
|
|
1292
|
+
extractionFields?: AgentExtractionField[];
|
|
1293
|
+
/** Include message text, or emit metadata-only SMS payloads. Defaults to full. */
|
|
1294
|
+
contentMode?: 'full' | 'metadata_only';
|
|
1295
|
+
}
|
|
1296
|
+
|
|
1297
|
+
export type WebhookEndpointUpdate = Partial<Omit<WebhookEndpointInput, 'authHeaders'>> & {
|
|
1298
|
+
authHeaders?: WebhookEndpointAuthHeaderUpdate[];
|
|
1299
|
+
};
|
|
1300
|
+
|
|
1301
|
+
export interface WebhookEndpoint {
|
|
1302
|
+
id: string;
|
|
1303
|
+
name: string;
|
|
1304
|
+
url: string;
|
|
1305
|
+
events: WorkspaceWebhookEventType[];
|
|
1306
|
+
allAgents: boolean;
|
|
1307
|
+
agentIds: string[];
|
|
1308
|
+
filterTags: Record<string, string>;
|
|
1309
|
+
headers: Record<string, string>;
|
|
1310
|
+
authHeaders: Array<{ name: string; configured: true }>;
|
|
1311
|
+
timeoutMs: number;
|
|
1312
|
+
signingSecretSource: 'workspace' | 'custom';
|
|
1313
|
+
hasCustomSigningSecret: boolean;
|
|
1314
|
+
extractionFields: AgentExtractionField[];
|
|
1315
|
+
contentMode: 'full' | 'metadata_only';
|
|
1316
|
+
legacyManaged: boolean;
|
|
1317
|
+
createdAt: string;
|
|
1318
|
+
updatedAt: string;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
export interface WebhookDeliveryListParams {
|
|
1322
|
+
endpointId?: string;
|
|
1323
|
+
event?: WebhookEventType;
|
|
1324
|
+
agentId?: string;
|
|
1325
|
+
status?: WebhookDeliveryStatus;
|
|
1326
|
+
sessionId?: string;
|
|
1327
|
+
eventId?: string;
|
|
1328
|
+
from?: string;
|
|
1329
|
+
to?: string;
|
|
1330
|
+
cursor?: string;
|
|
1331
|
+
limit?: number;
|
|
1332
|
+
}
|
|
1333
|
+
|
|
1334
|
+
export interface WebhookDelivery {
|
|
1335
|
+
id: string;
|
|
1336
|
+
eventId: string;
|
|
1337
|
+
endpointId: string;
|
|
1338
|
+
endpointName: string;
|
|
1339
|
+
endpointKind: 'workspace' | 'imessage';
|
|
1340
|
+
endpointDeleted: boolean;
|
|
1341
|
+
event: WebhookEventType;
|
|
1342
|
+
sessionId: string | null;
|
|
1343
|
+
agentId: string | null;
|
|
1344
|
+
webhookTags: Record<string, string>;
|
|
1345
|
+
status: WebhookDeliveryStatus;
|
|
1346
|
+
attempts: number;
|
|
1347
|
+
httpStatus: number | null;
|
|
1348
|
+
error: string | null;
|
|
1349
|
+
occurredAt: string;
|
|
1350
|
+
expiresAt: string;
|
|
1351
|
+
deliveredAt: string | null;
|
|
1352
|
+
createdAt: string;
|
|
1353
|
+
/** False for provider-retried iMessage subscriber deliveries. */
|
|
1354
|
+
canRedeliver: boolean;
|
|
1355
|
+
}
|
|
1356
|
+
|
|
1357
|
+
export interface WebhookDeliveryEndpointOption {
|
|
1358
|
+
id: string;
|
|
1359
|
+
name: string;
|
|
1360
|
+
kind: 'workspace' | 'imessage';
|
|
1361
|
+
deleted: boolean;
|
|
1362
|
+
}
|
|
1363
|
+
|
|
1364
|
+
export interface WebhookDeliveryPage {
|
|
1365
|
+
data: WebhookDelivery[];
|
|
1366
|
+
nextCursor: string | null;
|
|
1367
|
+
endpointOptions: WebhookDeliveryEndpointOption[];
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
export interface WebhookDeliveryAttempt {
|
|
1371
|
+
id: string;
|
|
1372
|
+
attemptNumber: number;
|
|
1373
|
+
trigger: 'automatic' | 'manual';
|
|
1374
|
+
requestUrl: string;
|
|
1375
|
+
requestHeaders: Record<string, string>;
|
|
1376
|
+
requestBody: Record<string, unknown>;
|
|
1377
|
+
responseStatus: number | null;
|
|
1378
|
+
responseBody: string | null;
|
|
1379
|
+
responseTruncated: boolean;
|
|
1380
|
+
durationMs: number;
|
|
1381
|
+
error: string | null;
|
|
1382
|
+
createdAt: string;
|
|
1383
|
+
}
|
|
1384
|
+
|
|
1385
|
+
export interface WebhookDeliveryDetail extends Omit<WebhookDelivery, 'attempts'> {
|
|
1386
|
+
attemptCount: number;
|
|
1387
|
+
requestPayload: Record<string, unknown>;
|
|
1388
|
+
attempts: WebhookDeliveryAttempt[];
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
/**
|
|
1392
|
+
* One prompt-variable registry entry. `defaultValue` fills the variable when a
|
|
1393
|
+
* session/dial call omits it (empty string = declared optional: renders blank
|
|
1394
|
+
* and `{% if %}` branches false). Without a default the variable is required
|
|
1395
|
+
* per call — omitting it fails session create with 400
|
|
1396
|
+
* `MISSING_TEMPLATE_VARIABLES`. Names may not use the reserved `system.`
|
|
1397
|
+
* namespace.
|
|
1398
|
+
*/
|
|
1399
|
+
export interface AgentPromptVariable {
|
|
1400
|
+
name: string;
|
|
1401
|
+
defaultValue?: string;
|
|
1402
|
+
description?: string;
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1405
|
+
/** Turn-taking configuration for cascaded agents. Realtime agents ignore VAD. */
|
|
1406
|
+
export interface AgentTurnHandling {
|
|
1407
|
+
/** Local VAD provider. Omit to use Silero. */
|
|
1408
|
+
vad?: { provider: 'silero' | 'ai-coustics' };
|
|
1409
|
+
/**
|
|
1410
|
+
* Caller-leg input enhancement (ai-coustics). Omit for the platform default;
|
|
1411
|
+
* `enabled: false` turns it off; `model` is plain Quail (default) or Quail Voice
|
|
1412
|
+
* Focus (primary-speaker isolation, explicit opt-in).
|
|
1413
|
+
*/
|
|
1414
|
+
noiseCancellation?: { enabled: boolean; model?: 'quail' | 'quail-voice-focus' };
|
|
1415
|
+
profile?: 'conversational' | 'ivr' | 'ivr_patient';
|
|
1416
|
+
endpointing?: { minDelay?: number; maxDelay?: number };
|
|
1417
|
+
interruption?: {
|
|
1418
|
+
mode?: 'adaptive' | 'vad';
|
|
1419
|
+
minDuration?: number;
|
|
1420
|
+
minWords?: number;
|
|
1421
|
+
};
|
|
1422
|
+
turnDetection?: boolean | 'stt';
|
|
1423
|
+
contextThreshold?: boolean;
|
|
1424
|
+
textGate?: boolean;
|
|
1425
|
+
turnDetector?: 'smart_turn' | 'speko_turn_v1';
|
|
1426
|
+
dtmfToolDescription?: string;
|
|
1427
|
+
amdPrompt?: string;
|
|
1428
|
+
waitForCallee?: boolean;
|
|
1429
|
+
onMachine?: 'hangup' | 'leave_message' | 'agent_decides';
|
|
1430
|
+
voicemailMessage?: string;
|
|
1431
|
+
}
|
|
1432
|
+
|
|
1433
|
+
export interface AgentRow {
|
|
1434
|
+
id: string;
|
|
1435
|
+
organizationId: string;
|
|
1436
|
+
name: string;
|
|
1437
|
+
systemPrompt: string;
|
|
1438
|
+
voice: string | null;
|
|
1439
|
+
intent: AgentIntent;
|
|
1440
|
+
llmOptions: AgentLlmOptions | null;
|
|
1441
|
+
stackPreferences: AgentStackPreferences | null;
|
|
1442
|
+
sttOptions: AgentSttOptions | null;
|
|
1443
|
+
backgroundAudio: AgentBackgroundAudio | null;
|
|
1444
|
+
speechNormalization: AgentSpeechNormalization | null;
|
|
1445
|
+
turnHandling: AgentTurnHandling | null;
|
|
1446
|
+
/** @deprecated Use organization-owned `speko.webhooks` endpoints. */
|
|
1447
|
+
webhooks: AgentWebhooksSerialized | null;
|
|
1448
|
+
/**
|
|
1449
|
+
* Post-call extraction schema on the agent itself — no webhook required.
|
|
1450
|
+
* Merged with `webhooks.postCall.extractionFields`; the agent-level
|
|
1451
|
+
* definition wins on a name collision.
|
|
1452
|
+
*/
|
|
1453
|
+
extractionFields: AgentExtractionField[];
|
|
1454
|
+
/** Prompt-variable registry. Returned on single-agent reads; null = empty. */
|
|
1455
|
+
promptVariables?: AgentPromptVariable[] | null;
|
|
1456
|
+
createdAt: string;
|
|
1457
|
+
updatedAt: string;
|
|
1458
|
+
}
|
|
1459
|
+
|
|
1460
|
+
export interface AgentCreateParams {
|
|
1461
|
+
name: string;
|
|
1462
|
+
systemPrompt: string;
|
|
1463
|
+
voice?: string;
|
|
1464
|
+
intent: AgentIntent;
|
|
1465
|
+
llmOptions?: AgentLlmOptions;
|
|
1466
|
+
stackPreferences?: AgentStackPreferences;
|
|
1467
|
+
sttOptions?: AgentSttOptions;
|
|
1468
|
+
backgroundAudio?: AgentBackgroundAudio;
|
|
1469
|
+
speechNormalization?: AgentSpeechNormalization;
|
|
1470
|
+
turnHandling?: AgentTurnHandling;
|
|
1471
|
+
/** @deprecated Use `speko.webhooks.create()` after creating the agent. */
|
|
1472
|
+
webhooks?: AgentWebhooksCreate;
|
|
1473
|
+
/**
|
|
1474
|
+
* Post-call extraction schema on the agent itself — no webhook required.
|
|
1475
|
+
* Merged with `webhooks.postCall.extractionFields`; the agent-level
|
|
1476
|
+
* definition wins on a name collision.
|
|
1477
|
+
*/
|
|
1478
|
+
extractionFields?: AgentExtractionField[];
|
|
1479
|
+
/** Declare the prompt's `{{variables}}` with per-agent defaults/descriptions. */
|
|
1480
|
+
promptVariables?: AgentPromptVariable[];
|
|
1481
|
+
}
|
|
1482
|
+
|
|
1483
|
+
export type AgentUpdateParams = Partial<Omit<AgentCreateParams, 'webhooks' | 'turnHandling'>> & {
|
|
1484
|
+
/** Set to null to clear all stored turn-taking overrides. */
|
|
1485
|
+
turnHandling?: AgentTurnHandling | null;
|
|
1486
|
+
/** @deprecated Use `speko.webhooks.update()` for organization-owned endpoints. */
|
|
1487
|
+
webhooks?: AgentWebhooksUpdate | null;
|
|
1488
|
+
/**
|
|
1489
|
+
* Post-call extraction schema on the agent itself — no webhook required.
|
|
1490
|
+
* Merged with `webhooks.postCall.extractionFields`; the agent-level
|
|
1491
|
+
* definition wins on a name collision.
|
|
1492
|
+
*/
|
|
1493
|
+
/** `null` clears the schema. */
|
|
1494
|
+
extractionFields?: AgentExtractionField[] | null;
|
|
1495
|
+
};
|
|
1496
|
+
|
|
1497
|
+
// ─── Calls ───────────────────────────────────────────────────────────
|
|
1498
|
+
|
|
1499
|
+
export interface CallTranscriptEntry {
|
|
1500
|
+
id: string;
|
|
1501
|
+
index: number;
|
|
1502
|
+
source: 'user' | 'agent' | 'system';
|
|
1503
|
+
text: string;
|
|
1504
|
+
started_at: string;
|
|
1505
|
+
ended_at: string | null;
|
|
1506
|
+
provider: string | null;
|
|
1507
|
+
model: string | null;
|
|
1508
|
+
metadata: Record<string, unknown>;
|
|
1509
|
+
eou_ms?: number | null;
|
|
1510
|
+
llm_ttft_ms?: number | null;
|
|
1511
|
+
tts_ttfb_ms?: number | null;
|
|
1512
|
+
latency_status?: 'partial' | 'complete' | 'interrupted' | 'error' | null;
|
|
1513
|
+
conversational_latency_ms?: number | null;
|
|
1514
|
+
}
|
|
1515
|
+
|
|
1516
|
+
export interface CallCostLine {
|
|
1517
|
+
provider: string;
|
|
1518
|
+
metric: string;
|
|
1519
|
+
quantity: number;
|
|
1520
|
+
keySource: KeySource;
|
|
1521
|
+
costMicroUsd: string;
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
export interface CallReportWebhookDelivery {
|
|
1525
|
+
endpointId: string;
|
|
1526
|
+
deliveryId: string;
|
|
1527
|
+
eventId: string;
|
|
1528
|
+
delivered: boolean;
|
|
1529
|
+
status: number | null;
|
|
1530
|
+
error: string | null;
|
|
1531
|
+
createdAt: string;
|
|
1532
|
+
}
|
|
1533
|
+
|
|
1534
|
+
export interface CallReport {
|
|
1535
|
+
session_id: string;
|
|
1536
|
+
organization_id: string;
|
|
1537
|
+
summary: string;
|
|
1538
|
+
outcome: string;
|
|
1539
|
+
structured_data: Record<string, unknown>;
|
|
1540
|
+
/**
|
|
1541
|
+
* Caller-defined extraction values, keyed by field name — the same object the
|
|
1542
|
+
* `call.report` webhook delivers. `{}` when the agent declares no fields.
|
|
1543
|
+
*/
|
|
1544
|
+
custom_data: Record<string, unknown>;
|
|
1545
|
+
transcript: { entries: CallTranscriptEntry[] };
|
|
1546
|
+
cost_micro_usd: string;
|
|
1547
|
+
cost_breakdown: CallCostLine[];
|
|
1548
|
+
artifacts: Record<string, unknown>;
|
|
1549
|
+
metadata: Record<string, unknown>;
|
|
1550
|
+
scheduled_callback: ScheduledCallback | Record<string, unknown> | null;
|
|
1551
|
+
analysis_status: 'heuristic' | 'completed' | 'failed';
|
|
1552
|
+
analysis_provider: string | null;
|
|
1553
|
+
analysis_model: string | null;
|
|
1554
|
+
analysis_error: string | null;
|
|
1555
|
+
analysis_completed_at: string | null;
|
|
1556
|
+
/** @deprecated Aggregate retained through the current SDK major version. */
|
|
1557
|
+
post_call_webhook_status: 'not_configured' | 'pending' | 'delivered' | 'failed';
|
|
1558
|
+
/** @deprecated Aggregate retained through the current SDK major version. */
|
|
1559
|
+
post_call_webhook_attempts: number;
|
|
1560
|
+
/** @deprecated Aggregate retained through the current SDK major version. */
|
|
1561
|
+
post_call_webhook_next_retry_at: string | null;
|
|
1562
|
+
/** @deprecated Aggregate retained through the current SDK major version. */
|
|
1563
|
+
post_call_webhook_delivered_at: string | null;
|
|
1564
|
+
/** @deprecated Aggregate retained through the current SDK major version. */
|
|
1565
|
+
post_call_webhook_error: string | null;
|
|
1566
|
+
/** Canonical per-endpoint results; singular post-call fields are deprecated aggregates. */
|
|
1567
|
+
webhook_deliveries: CallReportWebhookDelivery[];
|
|
1568
|
+
created_at: string;
|
|
1569
|
+
updated_at: string;
|
|
1570
|
+
}
|
|
1571
|
+
|
|
1572
|
+
export type ScheduledCallbackStatus =
|
|
1573
|
+
| 'scheduled'
|
|
1574
|
+
| 'dispatching'
|
|
1575
|
+
| 'dispatched'
|
|
1576
|
+
| 'cancelled'
|
|
1577
|
+
| 'failed';
|
|
1578
|
+
|
|
1579
|
+
export interface ScheduledCallback {
|
|
1580
|
+
id: string;
|
|
1581
|
+
organization_id: string;
|
|
1582
|
+
source_session_id: string | null;
|
|
1583
|
+
created_session_id: string | null;
|
|
1584
|
+
agent_id: string | null;
|
|
1585
|
+
phone_number_id: string | null;
|
|
1586
|
+
to_number: string;
|
|
1587
|
+
from_number: string | null;
|
|
1588
|
+
scheduled_at: string;
|
|
1589
|
+
status: ScheduledCallbackStatus;
|
|
1590
|
+
reason: string | null;
|
|
1591
|
+
instructions: string | null;
|
|
1592
|
+
summary: string | null;
|
|
1593
|
+
pipeline_config: Record<string, unknown>;
|
|
1594
|
+
metadata: Record<string, unknown>;
|
|
1595
|
+
failure_cause: string | null;
|
|
1596
|
+
attempted_at: string | null;
|
|
1597
|
+
dispatched_at: string | null;
|
|
1598
|
+
cancelled_at: string | null;
|
|
1599
|
+
created_at: string;
|
|
1600
|
+
updated_at: string;
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
export interface ScheduledCallbacksListParams {
|
|
1604
|
+
status?: ScheduledCallbackStatus;
|
|
1605
|
+
sourceSessionId?: string;
|
|
1606
|
+
limit?: number;
|
|
1607
|
+
}
|
|
1608
|
+
|
|
1609
|
+
export interface CancelScheduledCallbackParams {
|
|
1610
|
+
reason?: string;
|
|
1611
|
+
}
|
|
1612
|
+
|
|
1613
|
+
export interface FinalizeCallReportParams {
|
|
1614
|
+
forceAnalysis?: boolean;
|
|
1615
|
+
retryWebhook?: boolean;
|
|
1616
|
+
}
|
|
1617
|
+
|
|
1618
|
+
export interface FinalizeCallReportResult {
|
|
1619
|
+
session_id: string;
|
|
1620
|
+
summary: string;
|
|
1621
|
+
outcome: string;
|
|
1622
|
+
cost_micro_usd: string;
|
|
1623
|
+
/** @deprecated Aggregate retained through the current SDK major version. */
|
|
1624
|
+
webhook: unknown;
|
|
1625
|
+
webhook_deliveries: CallReportWebhookDelivery[];
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
export interface CallRecording {
|
|
1629
|
+
url: string;
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
export interface WebJoinParams {
|
|
1633
|
+
/** Display name other participants (and transcripts) see for the joiner. */
|
|
1634
|
+
displayName?: string;
|
|
1635
|
+
}
|
|
1636
|
+
|
|
1637
|
+
export interface WebJoinResult {
|
|
1638
|
+
/** LiveKit access token for the live call's room. Mint at click time — short TTL. */
|
|
1639
|
+
token: string;
|
|
1640
|
+
/** Public LiveKit URL the browser connects to (pass both to `@spekoai/client`). */
|
|
1641
|
+
url: string;
|
|
1642
|
+
/** Participant identity minted for this join (unique per join). */
|
|
1643
|
+
identity: string;
|
|
1644
|
+
roomName: string;
|
|
1645
|
+
/** ISO timestamp the token stops being accepted for NEW connections. */
|
|
1646
|
+
expiresAt: string;
|
|
1647
|
+
}
|
|
1648
|
+
|
|
1649
|
+
export interface EndCallResult {
|
|
1650
|
+
ok: true;
|
|
1651
|
+
/** `ending` when teardown was requested; `already_ended` when the call was over. */
|
|
1652
|
+
status: 'ending' | 'already_ended';
|
|
1653
|
+
/** ISO timestamp, present only with `already_ended`. */
|
|
1654
|
+
ended_at?: string;
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
export interface CallEvent {
|
|
1658
|
+
id: string;
|
|
1659
|
+
session_id: string | null;
|
|
1660
|
+
organization_id: string;
|
|
1661
|
+
provider: 'livekit' | 'telnyx' | 'speko' | string;
|
|
1662
|
+
event_type: string;
|
|
1663
|
+
status: string | null;
|
|
1664
|
+
failure_cause: string | null;
|
|
1665
|
+
sip_status_code: number | null;
|
|
1666
|
+
sip_status: string | null;
|
|
1667
|
+
occurred_at: string;
|
|
1668
|
+
payload: Record<string, unknown>;
|
|
1669
|
+
created_at: string;
|
|
1670
|
+
}
|
|
1671
|
+
|
|
1672
|
+
export interface CallTransfer {
|
|
1673
|
+
id: string;
|
|
1674
|
+
session_id: string;
|
|
1675
|
+
organization_id: string;
|
|
1676
|
+
kind: 'blind' | 'warm';
|
|
1677
|
+
status: 'requested' | 'screening' | 'bridging' | 'completed' | 'failed' | 'cancelled';
|
|
1678
|
+
transfer_to: string;
|
|
1679
|
+
from_room_name: string | null;
|
|
1680
|
+
consultation_room_name: string | null;
|
|
1681
|
+
caller_participant_identity: string | null;
|
|
1682
|
+
recipient_participant_identity: string | null;
|
|
1683
|
+
outbound_trunk_id: string | null;
|
|
1684
|
+
screening_prompt: string | null;
|
|
1685
|
+
summary: string | null;
|
|
1686
|
+
failure_cause: string | null;
|
|
1687
|
+
metadata: Record<string, unknown>;
|
|
1688
|
+
created_at: string;
|
|
1689
|
+
updated_at: string;
|
|
1690
|
+
completed_at: string | null;
|
|
1691
|
+
}
|
|
1692
|
+
|
|
1693
|
+
export interface CallTransferResponse extends CallTransfer {
|
|
1694
|
+
routing_attempts?: (CallTransfer | null)[];
|
|
1695
|
+
next_transfer?: CallTransfer | null;
|
|
1696
|
+
fallback?: WarmTransferFallbackResult | null;
|
|
1697
|
+
}
|
|
1698
|
+
|
|
1699
|
+
export interface CallDetail {
|
|
1700
|
+
id: string;
|
|
1701
|
+
call_id: string;
|
|
1702
|
+
resource_uri: string;
|
|
1703
|
+
agent_id: string | null;
|
|
1704
|
+
status: string;
|
|
1705
|
+
kind: string;
|
|
1706
|
+
room_name: string | null;
|
|
1707
|
+
language: string;
|
|
1708
|
+
pipeline_config: Record<string, unknown>;
|
|
1709
|
+
metadata: Record<string, unknown>;
|
|
1710
|
+
created_at: string;
|
|
1711
|
+
updated_at: string;
|
|
1712
|
+
ended_at: string | null;
|
|
1713
|
+
duration_seconds: number | null;
|
|
1714
|
+
recording_status: string | null;
|
|
1715
|
+
recording_duration_ms: number | null;
|
|
1716
|
+
recording_resource_uri: string;
|
|
1717
|
+
report: CallReport | null;
|
|
1718
|
+
transfers: CallTransfer[];
|
|
1719
|
+
transcript: { entries: CallTranscriptEntry[] };
|
|
1720
|
+
span_tree: Record<string, unknown>;
|
|
1721
|
+
}
|
|
1722
|
+
|
|
1723
|
+
export interface BlindTransferParams {
|
|
1724
|
+
to: string;
|
|
1725
|
+
participantIdentity?: string;
|
|
1726
|
+
playDialtone?: boolean;
|
|
1727
|
+
ringingTimeout?: number;
|
|
1728
|
+
headers?: Record<string, string>;
|
|
1729
|
+
}
|
|
1730
|
+
|
|
1731
|
+
export interface WarmTransferDestination {
|
|
1732
|
+
to: string;
|
|
1733
|
+
label?: string;
|
|
1734
|
+
outboundTrunkId?: string;
|
|
1735
|
+
screeningPrompt?: string;
|
|
1736
|
+
summary?: string;
|
|
1737
|
+
metadata?: Record<string, unknown>;
|
|
1738
|
+
}
|
|
1739
|
+
|
|
1740
|
+
export interface WarmTransferFallback {
|
|
1741
|
+
strategy?: 'return_to_assistant' | 'take_message' | 'end_call';
|
|
1742
|
+
message?: string;
|
|
1743
|
+
takeMessagePrompt?: string;
|
|
1744
|
+
holdAudioUrl?: string;
|
|
1745
|
+
}
|
|
1746
|
+
|
|
1747
|
+
export interface WarmTransferVoicemailDetection {
|
|
1748
|
+
mode?: 'agent' | 'amd' | 'disabled';
|
|
1749
|
+
enabled?: boolean;
|
|
1750
|
+
timeoutSeconds?: number;
|
|
1751
|
+
}
|
|
1752
|
+
|
|
1753
|
+
export interface WarmTransferFallbackResult {
|
|
1754
|
+
action: 'return_to_assistant' | 'take_message' | 'end_call';
|
|
1755
|
+
message: string;
|
|
1756
|
+
take_message_prompt: string | null;
|
|
1757
|
+
hold_audio_url: string | null;
|
|
1758
|
+
voicemail_detected: boolean;
|
|
1759
|
+
}
|
|
1760
|
+
|
|
1761
|
+
export interface WarmTransferParams {
|
|
1762
|
+
to?: string;
|
|
1763
|
+
destinations?: WarmTransferDestination[];
|
|
1764
|
+
from?: string;
|
|
1765
|
+
participantIdentity?: string;
|
|
1766
|
+
outboundTrunkId?: string;
|
|
1767
|
+
screeningPrompt?: string;
|
|
1768
|
+
summary?: string;
|
|
1769
|
+
ringingTimeout?: number;
|
|
1770
|
+
waitUntilAnswered?: boolean;
|
|
1771
|
+
fallback?: WarmTransferFallback;
|
|
1772
|
+
voicemailDetection?: WarmTransferVoicemailDetection;
|
|
1773
|
+
metadata?: Record<string, unknown>;
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
export interface CompleteWarmTransferParams {
|
|
1777
|
+
recipientParticipantIdentity?: string;
|
|
1778
|
+
summary?: string;
|
|
1779
|
+
}
|
|
1780
|
+
|
|
1781
|
+
export interface CancelWarmTransferParams {
|
|
1782
|
+
reason?: string;
|
|
1783
|
+
summary?: string;
|
|
1784
|
+
tryNext?: boolean;
|
|
1785
|
+
voicemailDetected?: boolean;
|
|
1786
|
+
}
|
|
1787
|
+
|
|
1788
|
+
export interface AgentCallListParams {
|
|
1789
|
+
/** Max rows. Default 50, server-capped at 100. */
|
|
1790
|
+
limit?: number;
|
|
1791
|
+
/** ISO timestamp returned as `next_cursor` from the previous page. */
|
|
1792
|
+
cursor?: string;
|
|
1793
|
+
/** ISO timestamp lower bound for calls to include. */
|
|
1794
|
+
since?: string;
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
export interface AgentCallListEntry {
|
|
1798
|
+
id: string;
|
|
1799
|
+
call_id: string;
|
|
1800
|
+
resource_uri: string;
|
|
1801
|
+
agent_id: string;
|
|
1802
|
+
status: string;
|
|
1803
|
+
kind: string;
|
|
1804
|
+
room_name: string | null;
|
|
1805
|
+
language: string;
|
|
1806
|
+
created_at: string;
|
|
1807
|
+
ended_at: string | null;
|
|
1808
|
+
duration_seconds: number | null;
|
|
1809
|
+
recording_status: string | null;
|
|
1810
|
+
}
|
|
1811
|
+
|
|
1812
|
+
export interface AgentCallListPage {
|
|
1813
|
+
calls: AgentCallListEntry[];
|
|
1814
|
+
entries: AgentCallListEntry[];
|
|
1815
|
+
next_cursor: string | null;
|
|
1816
|
+
}
|
|
1817
|
+
|
|
1818
|
+
// ─── Agent tools ─────────────────────────────────────────────────────
|
|
1819
|
+
|
|
1820
|
+
export interface AgentToolSourceInline {
|
|
1821
|
+
kind: 'inline';
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
/**
|
|
1825
|
+
* HTTP verb for a webhook tool. Omitting it means `POST`, so a tool
|
|
1826
|
+
* written before this field existed is unchanged.
|
|
1827
|
+
*
|
|
1828
|
+
* `GET` and `DELETE` send NO request body — not a `body` template and not
|
|
1829
|
+
* the default envelope either. Pairing one with `body` is rejected with
|
|
1830
|
+
* `422 WEBHOOK_TEMPLATE_INVALID` rather than silently dropping the body.
|
|
1831
|
+
*/
|
|
1832
|
+
export type AgentToolWebhookMethod = 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'GET';
|
|
1833
|
+
|
|
1834
|
+
/**
|
|
1835
|
+
* JSON body template for a webhook tool.
|
|
1836
|
+
*
|
|
1837
|
+
* Omit it and Speko sends its fixed envelope —
|
|
1838
|
+
* `{tool, args, idempotency_key, session_id, tool_call_id}` — unchanged.
|
|
1839
|
+
* Supply one and it REPLACES that envelope, so a tool can post the shape
|
|
1840
|
+
* a third-party API actually wants.
|
|
1841
|
+
*
|
|
1842
|
+
* Every string leaf interpolates `{{name}}`: any session `variables` or
|
|
1843
|
+
* `toolSecrets` entry, plus these reserved names —
|
|
1844
|
+
*
|
|
1845
|
+
* | Name | Substitutes |
|
|
1846
|
+
* | --------------------- | ---------------------------------------------------- |
|
|
1847
|
+
* | `{{tool_name}}` | the tool's name |
|
|
1848
|
+
* | `{{session_id}}` | the session id |
|
|
1849
|
+
* | `{{tool_call_id}}` | the model's tool-call id |
|
|
1850
|
+
* | `{{idempotency_key}}` | `<session_id>:<tool_call_id>` |
|
|
1851
|
+
* | `{{args.<name>}}` | one argument, JSON type preserved |
|
|
1852
|
+
* | `{{args}}` | the whole arguments object — whole values only |
|
|
1853
|
+
*
|
|
1854
|
+
* Reserved names win over a session value of the same name. `{{args}}`
|
|
1855
|
+
* must be the ENTIRE value of a key; embedding it in a longer string is
|
|
1856
|
+
* rejected at write time instead of being JSON-stringified into it.
|
|
1857
|
+
*
|
|
1858
|
+
* Limits: 8 KB serialized, 8 levels of nesting, and no `__proto__`,
|
|
1859
|
+
* `constructor` or `prototype` key. A URL whose ORIGIN is templated may
|
|
1860
|
+
* not carry a body template at all — see the tool-calling guide.
|
|
1861
|
+
*/
|
|
1862
|
+
export type AgentToolWebhookBody = Record<string, unknown> | unknown[];
|
|
1863
|
+
|
|
1864
|
+
/**
|
|
1865
|
+
* Webhook source as sent to {@link AgentTools.create}. The plaintext
|
|
1866
|
+
* `secret` is encrypted server-side; the returned row carries
|
|
1867
|
+
* `secretRef` instead.
|
|
1868
|
+
*/
|
|
1869
|
+
export interface AgentToolSourceWebhookCreate {
|
|
1870
|
+
kind: 'webhook';
|
|
1871
|
+
url: string;
|
|
1872
|
+
/** Plaintext shared secret. Encrypted server-side at write time. */
|
|
1873
|
+
secret: string;
|
|
1874
|
+
headers?: Record<string, string>;
|
|
1875
|
+
/** Secret-referenced outbound auth headers (e.g. a Bearer token your endpoint requires). */
|
|
1876
|
+
authHeaders?: AgentWebhookAuthHeaderInput[];
|
|
1877
|
+
/** HTTP verb. Omit for `POST`. `GET`/`DELETE` send no body and reject `body`. */
|
|
1878
|
+
method?: AgentToolWebhookMethod;
|
|
1879
|
+
/** JSON body template replacing the default envelope. See {@link AgentToolWebhookBody}. */
|
|
1880
|
+
body?: AgentToolWebhookBody;
|
|
1881
|
+
timeoutMs?: number;
|
|
1882
|
+
}
|
|
1883
|
+
|
|
1884
|
+
/**
|
|
1885
|
+
* Webhook source as returned by the API. The plaintext secret never
|
|
1886
|
+
* leaves the server — only the {@link secretRef} pointer is exposed.
|
|
1887
|
+
*/
|
|
1888
|
+
export interface AgentToolSourceWebhookSerialized {
|
|
1889
|
+
kind: 'webhook';
|
|
1890
|
+
url: string;
|
|
1891
|
+
/** Pointer into Speko's secrets store. */
|
|
1892
|
+
secretRef: string;
|
|
1893
|
+
headers?: Record<string, string>;
|
|
1894
|
+
/** Outbound auth-header pointers; values stay encrypted server-side. */
|
|
1895
|
+
authHeaders?: AgentWebhookAuthHeader[];
|
|
1896
|
+
/** Absent means `POST`. */
|
|
1897
|
+
method?: AgentToolWebhookMethod;
|
|
1898
|
+
/** The stored body template. Configuration, not a secret — returned as saved. */
|
|
1899
|
+
body?: AgentToolWebhookBody;
|
|
1900
|
+
timeoutMs?: number;
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
export interface AgentToolSourceBuiltin {
|
|
1904
|
+
kind: 'builtin';
|
|
1905
|
+
name: string;
|
|
1906
|
+
config?: unknown;
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
/**
|
|
1910
|
+
* Integration source — binds the tool to an org-installed Speko app action
|
|
1911
|
+
* (e.g. Google Calendar `create_event`). Speko resolves the installation and
|
|
1912
|
+
* runs the action server-side at completion time. The shape is identical on
|
|
1913
|
+
* create and in the serialized row (there is no secret to strip).
|
|
1914
|
+
*/
|
|
1915
|
+
export interface AgentToolSourceIntegration {
|
|
1916
|
+
kind: 'integration';
|
|
1917
|
+
installationId: string;
|
|
1918
|
+
appKey: string;
|
|
1919
|
+
actionKey: string;
|
|
1920
|
+
config?: unknown;
|
|
1921
|
+
}
|
|
1922
|
+
|
|
1923
|
+
/**
|
|
1924
|
+
* Webhook source as sent to {@link AgentTools.update}. Unlike the create
|
|
1925
|
+
* shape, `secret` is optional: omit it to keep the existing encrypted secret
|
|
1926
|
+
* untouched, or supply a new one to rotate it.
|
|
1927
|
+
*/
|
|
1928
|
+
export interface AgentToolSourceWebhookUpdate {
|
|
1929
|
+
kind: 'webhook';
|
|
1930
|
+
url: string;
|
|
1931
|
+
/** Plaintext shared secret. Omit to keep the existing stored secret; supply to rotate. */
|
|
1932
|
+
secret?: string;
|
|
1933
|
+
headers?: Record<string, string>;
|
|
1934
|
+
/** Secret-referenced outbound auth headers. Replaces the stored set; omit a `value` to keep it. */
|
|
1935
|
+
authHeaders?: AgentWebhookAuthHeaderInput[];
|
|
1936
|
+
/** HTTP verb. Omit for `POST`. `GET`/`DELETE` send no body and reject `body`. */
|
|
1937
|
+
method?: AgentToolWebhookMethod;
|
|
1938
|
+
/** JSON body template replacing the default envelope. See {@link AgentToolWebhookBody}. */
|
|
1939
|
+
body?: AgentToolWebhookBody;
|
|
1940
|
+
timeoutMs?: number;
|
|
1941
|
+
}
|
|
1942
|
+
|
|
1943
|
+
export type AgentToolSourceCreate =
|
|
1944
|
+
| AgentToolSourceInline
|
|
1945
|
+
| AgentToolSourceWebhookCreate
|
|
1946
|
+
| AgentToolSourceBuiltin
|
|
1947
|
+
| AgentToolSourceIntegration;
|
|
1948
|
+
|
|
1949
|
+
export type AgentToolSourceSerialized =
|
|
1950
|
+
| AgentToolSourceInline
|
|
1951
|
+
| AgentToolSourceWebhookSerialized
|
|
1952
|
+
| AgentToolSourceBuiltin
|
|
1953
|
+
| AgentToolSourceIntegration;
|
|
1954
|
+
|
|
1955
|
+
export type AgentToolSourceUpdate =
|
|
1956
|
+
| AgentToolSourceInline
|
|
1957
|
+
| AgentToolSourceWebhookUpdate
|
|
1958
|
+
| AgentToolSourceBuiltin
|
|
1959
|
+
| AgentToolSourceIntegration;
|
|
1960
|
+
|
|
1961
|
+
export interface AgentToolRow {
|
|
1962
|
+
id: string;
|
|
1963
|
+
agentId: string;
|
|
1964
|
+
name: string;
|
|
1965
|
+
description: string;
|
|
1966
|
+
parameters: Record<string, unknown>;
|
|
1967
|
+
source: AgentToolSourceSerialized;
|
|
1968
|
+
/** Spoken lead-in behavior before this tool executes. */
|
|
1969
|
+
preToolSpeech: ChatToolPreToolSpeech;
|
|
1970
|
+
createdAt: string;
|
|
1971
|
+
updatedAt: string;
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
export interface AgentToolCreateParams {
|
|
1975
|
+
name: string;
|
|
1976
|
+
description: string;
|
|
1977
|
+
parameters: Record<string, unknown>;
|
|
1978
|
+
source: AgentToolSourceCreate;
|
|
1979
|
+
/** Spoken lead-in behavior before the tool executes. Defaults to `auto`. */
|
|
1980
|
+
preToolSpeech?: ChatToolPreToolSpeech;
|
|
1981
|
+
}
|
|
1982
|
+
|
|
1983
|
+
export interface AgentToolUpdateParams {
|
|
1984
|
+
description?: string;
|
|
1985
|
+
parameters?: Record<string, unknown>;
|
|
1986
|
+
source?: AgentToolSourceUpdate;
|
|
1987
|
+
preToolSpeech?: ChatToolPreToolSpeech;
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
// ─── Knowledge bases ─────────────────────────────────────────────────
|
|
1991
|
+
|
|
1992
|
+
export interface KnowledgeBaseRow {
|
|
1993
|
+
id: string;
|
|
1994
|
+
organizationId: string;
|
|
1995
|
+
agentId: string;
|
|
1996
|
+
name: string;
|
|
1997
|
+
description: string | null;
|
|
1998
|
+
embeddingModel: string;
|
|
1999
|
+
documentCount: number;
|
|
2000
|
+
chunkCount: number;
|
|
2001
|
+
createdAt: string;
|
|
2002
|
+
updatedAt: string;
|
|
2003
|
+
}
|
|
2004
|
+
|
|
2005
|
+
export interface KnowledgeBaseCreateParams {
|
|
2006
|
+
agentId: string;
|
|
2007
|
+
name: string;
|
|
2008
|
+
description?: string;
|
|
2009
|
+
}
|
|
2010
|
+
|
|
2011
|
+
export interface KnowledgeBaseListParams {
|
|
2012
|
+
/** Filter to a single agent's KBs. */
|
|
2013
|
+
agentId?: string;
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
export type KnowledgeBaseDocumentStatus = 'pending' | 'processing' | 'ready' | 'failed';
|
|
2017
|
+
|
|
2018
|
+
export interface KnowledgeBaseDocumentRow {
|
|
2019
|
+
id: string;
|
|
2020
|
+
knowledgeBaseId: string;
|
|
2021
|
+
filename: string;
|
|
2022
|
+
contentType: string;
|
|
2023
|
+
sizeBytes: number;
|
|
2024
|
+
status: KnowledgeBaseDocumentStatus;
|
|
2025
|
+
errorMessage: string | null;
|
|
2026
|
+
chunkCount: number;
|
|
2027
|
+
metadata: Record<string, unknown> | null;
|
|
2028
|
+
createdAt: string;
|
|
2029
|
+
updatedAt: string;
|
|
2030
|
+
ingestedAt: string | null;
|
|
2031
|
+
}
|
|
2032
|
+
|
|
2033
|
+
export interface KnowledgeBaseDocumentCreateParams {
|
|
2034
|
+
filename: string;
|
|
2035
|
+
/** MIME type. Currently the ingest pipeline accepts `text/plain` and `text/markdown` (plus `text/x-markdown`, `application/x-markdown`). */
|
|
2036
|
+
contentType: string;
|
|
2037
|
+
sizeBytes: number;
|
|
2038
|
+
metadata?: Record<string, unknown>;
|
|
2039
|
+
}
|
|
2040
|
+
|
|
2041
|
+
export interface KnowledgeBaseDocumentUploadSpec {
|
|
2042
|
+
/** Signed GCS URL valid for `expiresInSeconds` from issuance. */
|
|
2043
|
+
url: string;
|
|
2044
|
+
method: 'PUT';
|
|
2045
|
+
/** Headers that MUST be sent on the PUT (Content-Type, length-range, etc.). */
|
|
2046
|
+
headers: Record<string, string>;
|
|
2047
|
+
expiresInSeconds: number;
|
|
2048
|
+
}
|
|
2049
|
+
|
|
2050
|
+
export interface KnowledgeBaseDocumentCreateResult {
|
|
2051
|
+
document: KnowledgeBaseDocumentRow;
|
|
2052
|
+
upload: KnowledgeBaseDocumentUploadSpec;
|
|
2053
|
+
}
|
|
2054
|
+
|
|
2055
|
+
/**
|
|
2056
|
+
* Convenience parameter shape for {@link KnowledgeBases.uploadDocument}.
|
|
2057
|
+
* The wrapper computes `sizeBytes` from `data` automatically.
|
|
2058
|
+
*/
|
|
2059
|
+
export interface KnowledgeBaseDocumentUploadParams {
|
|
2060
|
+
filename: string;
|
|
2061
|
+
contentType: string;
|
|
2062
|
+
data: ArrayBuffer | Uint8Array | Blob;
|
|
2063
|
+
metadata?: Record<string, unknown>;
|
|
2064
|
+
}
|
|
2065
|
+
|
|
2066
|
+
export interface KnowledgeBaseDocumentPollOptions {
|
|
2067
|
+
/** Polling interval in milliseconds. Default 2000. */
|
|
2068
|
+
intervalMs?: number;
|
|
2069
|
+
/** Total timeout in milliseconds. Default 120000 (2 min). */
|
|
2070
|
+
timeoutMs?: number;
|
|
2071
|
+
}
|
|
2072
|
+
|
|
2073
|
+
// --- Programmable voice -----------------------------------------------------
|
|
2074
|
+
|
|
2075
|
+
/**
|
|
2076
|
+
* Parameters for {@link CallControl.dial} — an outbound PSTN call placed by a
|
|
2077
|
+
* human broker, not by an AI agent. For an agent dial see
|
|
2078
|
+
* {@link VoiceDialParams}.
|
|
2079
|
+
*/
|
|
2080
|
+
export interface CallControlDialParams {
|
|
2081
|
+
/** Destination in E.164 format (e.g. "+12015551234"). */
|
|
2082
|
+
to: string;
|
|
2083
|
+
/**
|
|
2084
|
+
* Caller ID to present, E.164. Must be a number your org owns; falls back to
|
|
2085
|
+
* the org's default outbound number when omitted.
|
|
2086
|
+
*/
|
|
2087
|
+
from?: string;
|
|
2088
|
+
/** Opaque key/values stored on the call and echoed back on every read. */
|
|
2089
|
+
metadata?: Record<string, unknown>;
|
|
2090
|
+
}
|
|
2091
|
+
|
|
2092
|
+
/**
|
|
2093
|
+
* What {@link CallControl.dial} resolves to. The join credentials come back
|
|
2094
|
+
* *with* the call rather than from a second request, because the dialing
|
|
2095
|
+
* broker's softphone has to already be in the room when the far end answers —
|
|
2096
|
+
* fetch them afterwards and the first moments of the call are silence.
|
|
2097
|
+
*
|
|
2098
|
+
* Destructure both halves; `call` alone is not enough to be heard:
|
|
2099
|
+
*
|
|
2100
|
+
* ```ts
|
|
2101
|
+
* const { call, join } = await speko.callControl.dial({ to: '+12015551234' });
|
|
2102
|
+
* ```
|
|
2103
|
+
*/
|
|
2104
|
+
export interface CallControlDialResult {
|
|
2105
|
+
/** The call and both of its legs — the `controlId`s every later command needs. */
|
|
2106
|
+
readonly call: CallResource;
|
|
2107
|
+
/** Room credentials for the dialing broker's own browser leg. */
|
|
2108
|
+
readonly join: CallJoinCredentials;
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
/** Filters for {@link CallControl.list}. All optional; all AND-ed together. */
|
|
2112
|
+
export interface CallControlListParams {
|
|
2113
|
+
/**
|
|
2114
|
+
* Typed against the contract's `CallStatus` on purpose: the server validates
|
|
2115
|
+
* `?status=` against the same enum and rejects anything else, so a typo is a
|
|
2116
|
+
* compile error here instead of a `VALIDATION_ERROR` at runtime.
|
|
2117
|
+
*/
|
|
2118
|
+
status?: CallStatus;
|
|
2119
|
+
direction?: CallDirection;
|
|
2120
|
+
/**
|
|
2121
|
+
* Only calls with a browser leg owned by this broker. Unlike dialing, reading
|
|
2122
|
+
* another broker's calls is allowed — a supervisor view is a legitimate use of
|
|
2123
|
+
* an org-scoped credential.
|
|
2124
|
+
*/
|
|
2125
|
+
brokerId?: string;
|
|
2126
|
+
/** Newest first. Server-side default and cap apply. */
|
|
2127
|
+
limit?: number;
|
|
2128
|
+
}
|
|
2129
|
+
|
|
2130
|
+
// --- SMS messaging ---------------------------------------------------------
|
|
2131
|
+
|
|
2132
|
+
export type SmsMessageStatus =
|
|
2133
|
+
| 'queued'
|
|
2134
|
+
| 'scheduled'
|
|
2135
|
+
| 'submitting'
|
|
2136
|
+
| 'accepted'
|
|
2137
|
+
| 'sent'
|
|
2138
|
+
| 'delivered'
|
|
2139
|
+
| 'delivery_failed'
|
|
2140
|
+
| 'rejected'
|
|
2141
|
+
| 'submission_unknown'
|
|
2142
|
+
| 'canceled'
|
|
2143
|
+
| 'received';
|
|
2144
|
+
export type SmsMessageDirection = 'inbound' | 'outbound';
|
|
2145
|
+
export type SmsMessageOrigin = 'api' | 'dashboard' | 'agent_tool' | 'agent_auto_reply' | 'telnyx';
|
|
2146
|
+
|
|
2147
|
+
export interface SmsSegmentEstimate {
|
|
2148
|
+
readonly encoding: 'gsm7' | 'ucs2';
|
|
2149
|
+
readonly segments: number;
|
|
2150
|
+
readonly units: number;
|
|
2151
|
+
readonly per_segment: number;
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
export interface SmsMessage {
|
|
2155
|
+
readonly id: string;
|
|
2156
|
+
readonly conversation_id: string;
|
|
2157
|
+
readonly batch_id: string | null;
|
|
2158
|
+
readonly from_phone_number_id: string;
|
|
2159
|
+
readonly direction: SmsMessageDirection;
|
|
2160
|
+
readonly origin: SmsMessageOrigin;
|
|
2161
|
+
readonly from: string;
|
|
2162
|
+
readonly to: string;
|
|
2163
|
+
readonly text: string | null;
|
|
2164
|
+
readonly campaign_id: string | null;
|
|
2165
|
+
readonly brand_id: string | null;
|
|
2166
|
+
readonly campaign_snapshot: Record<string, unknown> | null;
|
|
2167
|
+
readonly consent_id: string | null;
|
|
2168
|
+
readonly consent_basis: string | null;
|
|
2169
|
+
readonly recipient_timezone: string | null;
|
|
2170
|
+
readonly requested_send_at: string | null;
|
|
2171
|
+
readonly effective_send_at: string | null;
|
|
2172
|
+
readonly terminal_at: string | null;
|
|
2173
|
+
readonly status: SmsMessageStatus;
|
|
2174
|
+
readonly provider_status: string | null;
|
|
2175
|
+
readonly encoding: 'gsm7' | 'ucs2' | null;
|
|
2176
|
+
readonly estimated_segments: number;
|
|
2177
|
+
readonly segment_count: number;
|
|
2178
|
+
readonly estimated: SmsSegmentEstimate;
|
|
2179
|
+
readonly charged_micro_usd: string;
|
|
2180
|
+
readonly provider_cost_micro_usd: string | null;
|
|
2181
|
+
readonly metadata: Record<string, unknown>;
|
|
2182
|
+
readonly error: { readonly code: string; readonly detail: string | null } | null;
|
|
2183
|
+
readonly created_at: string;
|
|
2184
|
+
readonly updated_at: string;
|
|
2185
|
+
}
|
|
2186
|
+
|
|
2187
|
+
export interface SmsPage<T> {
|
|
2188
|
+
readonly data: T[];
|
|
2189
|
+
readonly next_cursor: string | null;
|
|
2190
|
+
}
|
|
2191
|
+
|
|
2192
|
+
export interface SmsSendParams {
|
|
2193
|
+
readonly from_phone_number_id: string;
|
|
2194
|
+
readonly to: string;
|
|
2195
|
+
readonly text: string;
|
|
2196
|
+
readonly idempotencyKey: string;
|
|
2197
|
+
readonly send_at?: string;
|
|
2198
|
+
readonly consent_id?: string | null;
|
|
2199
|
+
readonly recipient_timezone?: string | null;
|
|
2200
|
+
readonly metadata?: Record<string, unknown>;
|
|
2201
|
+
}
|
|
2202
|
+
|
|
2203
|
+
export interface SmsMessageListParams {
|
|
2204
|
+
readonly conversation_id?: string;
|
|
2205
|
+
readonly batch_id?: string;
|
|
2206
|
+
readonly from_phone_number_id?: string;
|
|
2207
|
+
readonly recipient?: string;
|
|
2208
|
+
readonly campaign_id?: string;
|
|
2209
|
+
readonly status?: SmsMessageStatus;
|
|
2210
|
+
readonly direction?: SmsMessageDirection;
|
|
2211
|
+
readonly origin?: SmsMessageOrigin;
|
|
2212
|
+
readonly created_after?: string;
|
|
2213
|
+
readonly created_before?: string;
|
|
2214
|
+
readonly cursor?: string;
|
|
2215
|
+
readonly limit?: number;
|
|
2216
|
+
}
|
|
2217
|
+
|
|
2218
|
+
export interface SmsBatchRecipient {
|
|
2219
|
+
readonly to: string;
|
|
2220
|
+
readonly text: string;
|
|
2221
|
+
readonly consent_id?: string | null;
|
|
2222
|
+
readonly recipient_timezone?: string | null;
|
|
2223
|
+
readonly metadata?: Record<string, unknown>;
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
export interface SmsBatchCreateParams {
|
|
2227
|
+
readonly from_phone_number_id: string;
|
|
2228
|
+
readonly recipients: readonly SmsBatchRecipient[];
|
|
2229
|
+
readonly idempotencyKey: string;
|
|
2230
|
+
readonly send_at?: string;
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
export interface SmsBatch {
|
|
2234
|
+
readonly id: string;
|
|
2235
|
+
readonly from_phone_number_id: string;
|
|
2236
|
+
readonly status:
|
|
2237
|
+
| 'queued'
|
|
2238
|
+
| 'scheduled'
|
|
2239
|
+
| 'processing'
|
|
2240
|
+
| 'completed'
|
|
2241
|
+
| 'partially_failed'
|
|
2242
|
+
| 'failed'
|
|
2243
|
+
| 'canceled';
|
|
2244
|
+
readonly requested_send_at: string | null;
|
|
2245
|
+
readonly total_count: number;
|
|
2246
|
+
readonly accepted_count: number;
|
|
2247
|
+
readonly rejected_count: number;
|
|
2248
|
+
readonly delivered_count: number;
|
|
2249
|
+
readonly failed_count: number;
|
|
2250
|
+
readonly canceled_at: string | null;
|
|
2251
|
+
readonly completed_at: string | null;
|
|
2252
|
+
readonly created_at: string;
|
|
2253
|
+
readonly updated_at: string;
|
|
2254
|
+
}
|
|
2255
|
+
|
|
2256
|
+
export interface SmsConversation {
|
|
2257
|
+
readonly id: string;
|
|
2258
|
+
readonly phone_number_id: string;
|
|
2259
|
+
readonly remote_phone_number: string;
|
|
2260
|
+
readonly campaign_id: string | null;
|
|
2261
|
+
readonly campaign_snapshot: Record<string, unknown> | null;
|
|
2262
|
+
readonly status: 'open' | 'closed' | 'spam';
|
|
2263
|
+
readonly automation_status: 'disabled' | 'enabled' | 'paused';
|
|
2264
|
+
readonly assigned_user_id: string | null;
|
|
2265
|
+
readonly assigned_agent_id: string | null;
|
|
2266
|
+
readonly unread_count: number;
|
|
2267
|
+
readonly recipient_timezone: string | null;
|
|
2268
|
+
readonly last_inbound_at: string | null;
|
|
2269
|
+
readonly last_outbound_at: string | null;
|
|
2270
|
+
readonly last_message_at: string;
|
|
2271
|
+
readonly content_redacted_at: string | null;
|
|
2272
|
+
readonly created_at: string;
|
|
2273
|
+
readonly updated_at: string;
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
export interface SmsConversationListParams {
|
|
2277
|
+
readonly status?: SmsConversation['status'];
|
|
2278
|
+
readonly phone_number_id?: string;
|
|
2279
|
+
readonly assigned_user_id?: string;
|
|
2280
|
+
readonly assigned_agent_id?: string;
|
|
2281
|
+
readonly recipient?: string;
|
|
2282
|
+
readonly unread?: boolean;
|
|
2283
|
+
readonly cursor?: string;
|
|
2284
|
+
readonly limit?: number;
|
|
2285
|
+
}
|
|
2286
|
+
|
|
2287
|
+
export interface SmsConversationUpdate {
|
|
2288
|
+
readonly status?: SmsConversation['status'];
|
|
2289
|
+
readonly assigned_user_id?: string | null;
|
|
2290
|
+
readonly assigned_agent_id?: string | null;
|
|
2291
|
+
readonly automation_status?: SmsConversation['automation_status'];
|
|
2292
|
+
readonly recipient_timezone?: string | null;
|
|
2293
|
+
}
|
|
2294
|
+
|
|
2295
|
+
export interface SmsConversationSendParams {
|
|
2296
|
+
readonly text: string;
|
|
2297
|
+
readonly idempotencyKey: string;
|
|
2298
|
+
readonly send_at?: string;
|
|
2299
|
+
readonly consent_id?: string | null;
|
|
2300
|
+
readonly recipient_timezone?: string | null;
|
|
2301
|
+
readonly metadata?: Record<string, unknown>;
|
|
2302
|
+
}
|
|
2303
|
+
|
|
2304
|
+
export type SmsConsentSource =
|
|
2305
|
+
| 'inbound'
|
|
2306
|
+
| 'api'
|
|
2307
|
+
| 'keyword'
|
|
2308
|
+
| 'webform'
|
|
2309
|
+
| 'paper'
|
|
2310
|
+
| 'verbal'
|
|
2311
|
+
| 'import';
|
|
2312
|
+
|
|
2313
|
+
export interface SmsConsentInput {
|
|
2314
|
+
readonly recipient: string;
|
|
2315
|
+
readonly campaign_id: string;
|
|
2316
|
+
readonly source: SmsConsentSource;
|
|
2317
|
+
readonly proof_reference?: string | null;
|
|
2318
|
+
readonly proof?: string | null;
|
|
2319
|
+
readonly timezone?: string | null;
|
|
2320
|
+
readonly captured_at?: string;
|
|
2321
|
+
readonly expires_at?: string | null;
|
|
2322
|
+
readonly metadata?: Record<string, unknown>;
|
|
2323
|
+
}
|
|
2324
|
+
|
|
2325
|
+
export interface SmsConsent {
|
|
2326
|
+
readonly id: string;
|
|
2327
|
+
readonly recipient: string;
|
|
2328
|
+
readonly campaign_id: string;
|
|
2329
|
+
readonly status: 'active' | 'expired' | 'revoked';
|
|
2330
|
+
readonly source: SmsConsentSource;
|
|
2331
|
+
readonly proof_reference: string | null;
|
|
2332
|
+
readonly proof_hash: string | null;
|
|
2333
|
+
readonly timezone: string | null;
|
|
2334
|
+
readonly captured_at: string;
|
|
2335
|
+
readonly expires_at: string | null;
|
|
2336
|
+
readonly revoked_at: string | null;
|
|
2337
|
+
readonly revoked_reason: string | null;
|
|
2338
|
+
readonly metadata: Record<string, unknown>;
|
|
2339
|
+
readonly created_at: string;
|
|
2340
|
+
}
|
|
2341
|
+
|
|
2342
|
+
export interface SmsConsentListParams {
|
|
2343
|
+
readonly recipient?: string;
|
|
2344
|
+
readonly campaign_id?: string;
|
|
2345
|
+
readonly status?: SmsConsent['status'];
|
|
2346
|
+
readonly limit?: number;
|
|
2347
|
+
}
|
|
2348
|
+
|
|
2349
|
+
export interface SmsSuppression {
|
|
2350
|
+
readonly id: string;
|
|
2351
|
+
readonly recipient: string;
|
|
2352
|
+
readonly status: 'suppressed' | 'lifted';
|
|
2353
|
+
readonly keyword: string | null;
|
|
2354
|
+
readonly source_phone_number_id: string | null;
|
|
2355
|
+
readonly source_message_provider_id: string | null;
|
|
2356
|
+
readonly suppressed_at: string;
|
|
2357
|
+
readonly lifted_at: string | null;
|
|
2358
|
+
readonly updated_at: string;
|
|
2359
|
+
}
|
|
2360
|
+
|
|
2361
|
+
export interface SmsSettings {
|
|
2362
|
+
readonly messaging_profile_id: string | null;
|
|
2363
|
+
readonly messaging_profile_status: string;
|
|
2364
|
+
readonly webhook_config_version: number;
|
|
2365
|
+
readonly opt_out_config_version: number;
|
|
2366
|
+
readonly help_message: string;
|
|
2367
|
+
readonly opt_out_message: string;
|
|
2368
|
+
readonly opt_in_message: string;
|
|
2369
|
+
readonly retention_days: number;
|
|
2370
|
+
readonly quiet_hours_start: string;
|
|
2371
|
+
readonly quiet_hours_end: string;
|
|
2372
|
+
readonly default_timezone: string | null;
|
|
2373
|
+
readonly default_automation_enabled: boolean;
|
|
2374
|
+
readonly last_synced_at: string | null;
|
|
2375
|
+
readonly last_error: string | null;
|
|
2376
|
+
readonly updated_at: string;
|
|
2377
|
+
}
|
|
2378
|
+
|
|
2379
|
+
export type SmsSettingsUpdate = Partial<
|
|
2380
|
+
Pick<
|
|
2381
|
+
SmsSettings,
|
|
2382
|
+
| 'help_message'
|
|
2383
|
+
| 'opt_out_message'
|
|
2384
|
+
| 'opt_in_message'
|
|
2385
|
+
| 'retention_days'
|
|
2386
|
+
| 'quiet_hours_start'
|
|
2387
|
+
| 'quiet_hours_end'
|
|
2388
|
+
| 'default_timezone'
|
|
2389
|
+
| 'default_automation_enabled'
|
|
2390
|
+
>
|
|
2391
|
+
>;
|
|
2392
|
+
|
|
2393
|
+
export interface SmsConversationNote {
|
|
2394
|
+
readonly id: string;
|
|
2395
|
+
readonly conversation_id: string;
|
|
2396
|
+
readonly body: string | null;
|
|
2397
|
+
readonly created_by_user_id: string;
|
|
2398
|
+
readonly redacted_at: string | null;
|
|
2399
|
+
readonly created_at: string;
|
|
2400
|
+
}
|
|
2401
|
+
|
|
2402
|
+
export interface SmsStreamEvent {
|
|
2403
|
+
readonly event: string;
|
|
2404
|
+
readonly id?: string;
|
|
2405
|
+
readonly message_id: string;
|
|
2406
|
+
readonly conversation_id: string;
|
|
2407
|
+
readonly status: SmsMessageStatus;
|
|
2408
|
+
readonly occurred_at: string;
|
|
2409
|
+
}
|