@osmapi/osmtalk-sdk 0.2.0
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/README.md +159 -0
- package/dist/index.d.mts +520 -0
- package/dist/index.d.ts +520 -0
- package/dist/index.js +450 -0
- package/dist/index.mjs +422 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# @osmapi/osmtalk-sdk
|
|
2
|
+
|
|
3
|
+
Official TypeScript / JavaScript SDK for the [osmTalk](https://osmtalk.com) voice AI platform.
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install @osmapi/osmtalk-sdk
|
|
7
|
+
# or: pnpm add @osmapi/osmtalk-sdk
|
|
8
|
+
```
|
|
9
|
+
|
|
10
|
+
## Quick start
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
import { Osmtalk } from "@osmapi/osmtalk-sdk";
|
|
14
|
+
|
|
15
|
+
const client = new Osmtalk({ apiKey: process.env.OSMTALK_API_KEY! });
|
|
16
|
+
|
|
17
|
+
// Place an outbound call with per-call personalization
|
|
18
|
+
const call = await client.calls.outbound({
|
|
19
|
+
agentId: "agent_xxx",
|
|
20
|
+
phoneNumberId: "pn_xxx",
|
|
21
|
+
destination: "+919876543210",
|
|
22
|
+
dynamicVariables: {
|
|
23
|
+
first_name: "Arjun",
|
|
24
|
+
company: "Acme",
|
|
25
|
+
renewal_date: "May 28, 2026",
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
console.log("Call started:", call.callId);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Resources
|
|
33
|
+
|
|
34
|
+
| Resource | Operations |
|
|
35
|
+
|---|---|
|
|
36
|
+
| `client.agents` | `list`, `get`, `create`, `update`, `delete`, `connect`, `publishVersion`, `listVersions`, `getVersion`, `rollbackToVersion` |
|
|
37
|
+
| `client.calls` | `list`, `get`, `outbound`, `end`, `transfer` |
|
|
38
|
+
| `client.campaigns` | `list`, `get`, `create`, `update`, `delete`, `start`, `pause`, `resume`, `stop`, `report`, `uploadLeadsCsv`, `uploadLeads`, `listLeads` |
|
|
39
|
+
| `client.dnc` | `list`, `add`, `bulkAdd`, `remove` |
|
|
40
|
+
| `client.eval` | `simulate`, `createTestCase`, `listTestCases`, `runTestCase`, `runAll`, `listRuns`, `getRun` |
|
|
41
|
+
| `client.settings` | `get`, `getStorage`, `updateStorage`, `getWebhook`, `updateWebhook`, `getCompliance`, `updateCompliance` |
|
|
42
|
+
|
|
43
|
+
## Examples
|
|
44
|
+
|
|
45
|
+
### Run an outbound campaign
|
|
46
|
+
|
|
47
|
+
```ts
|
|
48
|
+
const camp = await client.campaigns.create({
|
|
49
|
+
name: "Q2 Renewals",
|
|
50
|
+
agentId: "agent_xxx",
|
|
51
|
+
phoneNumberId: "pn_xxx",
|
|
52
|
+
maxConcurrent: 5,
|
|
53
|
+
schedule: { timezone: "Asia/Kolkata", windowStart: "10:00", windowEnd: "18:00" },
|
|
54
|
+
retryPolicy: { maxAttempts: 3, backoffMinutes: 60, retryOn: ["no_answer", "busy"] },
|
|
55
|
+
webhookUrl: "https://your-crm/webhooks/osmtalk",
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
await client.campaigns.uploadLeadsCsv(camp.id, `
|
|
59
|
+
phone,first_name,renewal_date
|
|
60
|
+
+919876543210,Arjun,2026-05-28
|
|
61
|
+
+919876543211,Meera,2026-06-02
|
|
62
|
+
`.trim());
|
|
63
|
+
|
|
64
|
+
await client.campaigns.start(camp.id);
|
|
65
|
+
|
|
66
|
+
// Poll the report
|
|
67
|
+
const report = await client.campaigns.report(camp.id);
|
|
68
|
+
console.log(report.counts.byStatus);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Publish a new agent version and A/B test
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
// Publish current draft as v2
|
|
75
|
+
const v2 = await client.agents.publishVersion("agent_xxx", { label: "Tighter qualifier" });
|
|
76
|
+
|
|
77
|
+
// Call with v2 explicitly
|
|
78
|
+
await client.calls.outbound({ agentId: "agent_xxx", phoneNumberId: "pn_xxx", destination: "+919876543210", agentVersion: v2.version });
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Simulate before going live
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
const sim = await client.eval.simulate("agent_xxx", [
|
|
85
|
+
{ role: "user", content: "Hi, who's calling?" },
|
|
86
|
+
{ role: "user", content: "Sure, tell me more about renewal options" },
|
|
87
|
+
]);
|
|
88
|
+
|
|
89
|
+
for (const turn of sim.transcript) {
|
|
90
|
+
console.log(`${turn.role}: ${turn.content}`);
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Handle the webhook in Node.js
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
import crypto from "node:crypto";
|
|
98
|
+
import express from "express";
|
|
99
|
+
|
|
100
|
+
const app = express();
|
|
101
|
+
app.use(express.raw({ type: "application/json" }));
|
|
102
|
+
|
|
103
|
+
app.post("/webhooks/osmtalk", (req, res) => {
|
|
104
|
+
const sig = req.header("X-OsmTalk-Signature") ?? "";
|
|
105
|
+
const [algo, hex] = sig.split("=");
|
|
106
|
+
const expected = crypto
|
|
107
|
+
.createHmac("sha256", process.env.OSMTALK_WEBHOOK_SECRET!)
|
|
108
|
+
.update(req.body)
|
|
109
|
+
.digest("hex");
|
|
110
|
+
if (algo !== "sha256" || !crypto.timingSafeEqual(Buffer.from(hex, "hex"), Buffer.from(expected, "hex"))) {
|
|
111
|
+
return res.sendStatus(401);
|
|
112
|
+
}
|
|
113
|
+
const event = JSON.parse(req.body.toString());
|
|
114
|
+
if (event.event === "campaign.lead_completed" && event.lead.disposition === "qualified") {
|
|
115
|
+
console.log("Hot lead:", event.lead.variables.first_name);
|
|
116
|
+
}
|
|
117
|
+
res.json({ ok: true });
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Error handling
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
import { Osmtalk, OsmtalkError } from "@osmapi/osmtalk-sdk";
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
await client.calls.outbound({ /* ... */ });
|
|
128
|
+
} catch (err) {
|
|
129
|
+
if (err instanceof OsmtalkError) {
|
|
130
|
+
console.log("HTTP", err.status, err.body);
|
|
131
|
+
} else {
|
|
132
|
+
throw err;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
| Status | Meaning |
|
|
138
|
+
|---|---|
|
|
139
|
+
| 400 | Validation — `err.body.details` has zod field errors |
|
|
140
|
+
| 401 | Bad API key |
|
|
141
|
+
| 402 | Insufficient credits |
|
|
142
|
+
| 404 | Resource not found |
|
|
143
|
+
| 429 | Concurrency or rate limit |
|
|
144
|
+
| 5xx | Server error / provider outage |
|
|
145
|
+
|
|
146
|
+
## Options
|
|
147
|
+
|
|
148
|
+
```ts
|
|
149
|
+
new Osmtalk({
|
|
150
|
+
apiKey: "...",
|
|
151
|
+
baseUrl: "https://api.osmtalk.com", // optional override
|
|
152
|
+
timeoutMs: 30_000, // per-request timeout
|
|
153
|
+
fetch: customFetch, // optional (Node 18+ has global fetch)
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
## License
|
|
158
|
+
|
|
159
|
+
MIT
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* osmTalk TypeScript SDK
|
|
3
|
+
*
|
|
4
|
+
* import { Osmtalk } from "@osmapi/osmtalk-sdk";
|
|
5
|
+
* const client = new Osmtalk({ apiKey: process.env.OSMTALK_API_KEY! });
|
|
6
|
+
* const call = await client.calls.outbound({
|
|
7
|
+
* agentId: "agent_xxx",
|
|
8
|
+
* phoneNumberId: "pn_xxx",
|
|
9
|
+
* destination: "+919876543210",
|
|
10
|
+
* dynamicVariables: { first_name: "Arjun" },
|
|
11
|
+
* });
|
|
12
|
+
*/
|
|
13
|
+
interface OsmtalkOptions {
|
|
14
|
+
apiKey: string;
|
|
15
|
+
baseUrl?: string;
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
/** Custom fetch implementation (e.g. for testing). */
|
|
18
|
+
fetch?: typeof fetch;
|
|
19
|
+
}
|
|
20
|
+
interface DynamicVariables {
|
|
21
|
+
[key: string]: string | number | boolean;
|
|
22
|
+
}
|
|
23
|
+
interface AssistantOverride {
|
|
24
|
+
systemPrompt?: string;
|
|
25
|
+
welcomeMessage?: string;
|
|
26
|
+
llmProvider?: string;
|
|
27
|
+
llmModel?: string;
|
|
28
|
+
sttProvider?: string;
|
|
29
|
+
sttModel?: string;
|
|
30
|
+
sttLanguage?: string;
|
|
31
|
+
ttsProvider?: string;
|
|
32
|
+
ttsModel?: string;
|
|
33
|
+
ttsVoice?: string;
|
|
34
|
+
settings?: Record<string, unknown>;
|
|
35
|
+
}
|
|
36
|
+
interface CallStartRequest {
|
|
37
|
+
agentId: string;
|
|
38
|
+
phoneNumberId: string;
|
|
39
|
+
destination: string;
|
|
40
|
+
agentVersion?: number;
|
|
41
|
+
dynamicVariables?: DynamicVariables;
|
|
42
|
+
assistantOverride?: AssistantOverride;
|
|
43
|
+
metadata?: Record<string, unknown>;
|
|
44
|
+
}
|
|
45
|
+
interface CallRecord {
|
|
46
|
+
id: string;
|
|
47
|
+
agentId: string;
|
|
48
|
+
status: string;
|
|
49
|
+
channel: string;
|
|
50
|
+
startedAt: string;
|
|
51
|
+
endedAt?: string | null;
|
|
52
|
+
durationSeconds?: number | null;
|
|
53
|
+
recordingUrl?: string | null;
|
|
54
|
+
recordingMultiChannelUrl?: string | null;
|
|
55
|
+
transcript?: unknown;
|
|
56
|
+
analysis?: unknown;
|
|
57
|
+
analysisStatus?: string | null;
|
|
58
|
+
dynamicVariables?: DynamicVariables | null;
|
|
59
|
+
agentVersion?: number | null;
|
|
60
|
+
campaignId?: string | null;
|
|
61
|
+
campaignLeadId?: string | null;
|
|
62
|
+
disposition?: string | null;
|
|
63
|
+
metadata?: Record<string, unknown> | null;
|
|
64
|
+
[key: string]: unknown;
|
|
65
|
+
}
|
|
66
|
+
interface AgentRecord {
|
|
67
|
+
id: string;
|
|
68
|
+
name: string;
|
|
69
|
+
systemPrompt: string;
|
|
70
|
+
welcomeMessage?: string | null;
|
|
71
|
+
llmProvider: string;
|
|
72
|
+
llmModel: string;
|
|
73
|
+
sttProvider: string;
|
|
74
|
+
sttModel: string;
|
|
75
|
+
ttsProvider: string;
|
|
76
|
+
ttsModel: string;
|
|
77
|
+
ttsVoice?: string | null;
|
|
78
|
+
tools?: unknown;
|
|
79
|
+
settings?: unknown;
|
|
80
|
+
pronunciationDictionary?: unknown;
|
|
81
|
+
boostedKeywords?: unknown;
|
|
82
|
+
postCallAnalysis?: unknown;
|
|
83
|
+
currentVersion?: number | null;
|
|
84
|
+
isActive: boolean;
|
|
85
|
+
[key: string]: unknown;
|
|
86
|
+
}
|
|
87
|
+
interface CampaignRecord {
|
|
88
|
+
id: string;
|
|
89
|
+
name: string;
|
|
90
|
+
description?: string | null;
|
|
91
|
+
agentId: string;
|
|
92
|
+
agentVersion?: number | null;
|
|
93
|
+
phoneNumberId?: string | null;
|
|
94
|
+
status: "draft" | "scheduled" | "running" | "paused" | "completed" | "failed" | string;
|
|
95
|
+
totalLeads: number;
|
|
96
|
+
completedLeads: number;
|
|
97
|
+
qualifiedLeads: number;
|
|
98
|
+
failedLeads: number;
|
|
99
|
+
dncBlockedLeads: number;
|
|
100
|
+
startedAt?: string | null;
|
|
101
|
+
completedAt?: string | null;
|
|
102
|
+
scheduledStartAt?: string | null;
|
|
103
|
+
schedule?: Record<string, unknown> | null;
|
|
104
|
+
retryPolicy?: Record<string, unknown> | null;
|
|
105
|
+
maxConcurrent?: number | null;
|
|
106
|
+
webhookUrl?: string | null;
|
|
107
|
+
[key: string]: unknown;
|
|
108
|
+
}
|
|
109
|
+
interface CampaignCreateRequest {
|
|
110
|
+
name: string;
|
|
111
|
+
agentId: string;
|
|
112
|
+
phoneNumberId?: string;
|
|
113
|
+
agentVersion?: number;
|
|
114
|
+
description?: string;
|
|
115
|
+
scheduledStartAt?: string;
|
|
116
|
+
maxConcurrent?: number;
|
|
117
|
+
schedule?: {
|
|
118
|
+
timezone?: string;
|
|
119
|
+
windowStart?: string;
|
|
120
|
+
windowEnd?: string;
|
|
121
|
+
weekdays?: number[];
|
|
122
|
+
};
|
|
123
|
+
retryPolicy?: {
|
|
124
|
+
maxAttempts?: number;
|
|
125
|
+
backoffMinutes?: number;
|
|
126
|
+
retryOn?: Array<"no_answer" | "busy" | "failed" | "voicemail">;
|
|
127
|
+
};
|
|
128
|
+
webhookUrl?: string;
|
|
129
|
+
}
|
|
130
|
+
interface LeadRow {
|
|
131
|
+
phoneNumber: string;
|
|
132
|
+
variables?: Record<string, string | number | boolean>;
|
|
133
|
+
}
|
|
134
|
+
interface OsmtalkErrorBody {
|
|
135
|
+
error?: string;
|
|
136
|
+
message?: string;
|
|
137
|
+
code?: string;
|
|
138
|
+
details?: unknown;
|
|
139
|
+
[key: string]: unknown;
|
|
140
|
+
}
|
|
141
|
+
declare class OsmtalkError extends Error {
|
|
142
|
+
readonly status: number;
|
|
143
|
+
readonly body: OsmtalkErrorBody;
|
|
144
|
+
constructor(status: number, body: OsmtalkErrorBody);
|
|
145
|
+
}
|
|
146
|
+
declare class HttpClient {
|
|
147
|
+
private readonly baseUrl;
|
|
148
|
+
private readonly apiKey;
|
|
149
|
+
private readonly timeoutMs;
|
|
150
|
+
private readonly fetchImpl;
|
|
151
|
+
constructor(opts: OsmtalkOptions);
|
|
152
|
+
request<T>(method: string, path: string, body?: unknown, extraHeaders?: Record<string, string>, idempotencyKey?: string): Promise<T>;
|
|
153
|
+
}
|
|
154
|
+
declare class AgentsResource {
|
|
155
|
+
private readonly http;
|
|
156
|
+
constructor(http: HttpClient);
|
|
157
|
+
list(): Promise<AgentRecord[]>;
|
|
158
|
+
get(id: string): Promise<AgentRecord>;
|
|
159
|
+
create(input: Partial<AgentRecord>): Promise<AgentRecord>;
|
|
160
|
+
update(id: string, input: Partial<AgentRecord>): Promise<AgentRecord>;
|
|
161
|
+
delete(id: string): Promise<{
|
|
162
|
+
success: true;
|
|
163
|
+
}>;
|
|
164
|
+
publishVersion(id: string, opts?: {
|
|
165
|
+
label?: string;
|
|
166
|
+
notes?: string;
|
|
167
|
+
}): Promise<{
|
|
168
|
+
id: string;
|
|
169
|
+
version: number;
|
|
170
|
+
label?: string;
|
|
171
|
+
notes?: string;
|
|
172
|
+
snapshot: unknown;
|
|
173
|
+
}>;
|
|
174
|
+
listVersions(id: string): Promise<{
|
|
175
|
+
id: string;
|
|
176
|
+
version: number;
|
|
177
|
+
label?: string;
|
|
178
|
+
notes?: string;
|
|
179
|
+
snapshot: unknown;
|
|
180
|
+
}[]>;
|
|
181
|
+
getVersion(id: string, version: number): Promise<{
|
|
182
|
+
id: string;
|
|
183
|
+
version: number;
|
|
184
|
+
snapshot: unknown;
|
|
185
|
+
}>;
|
|
186
|
+
rollbackToVersion(id: string, version: number): Promise<{
|
|
187
|
+
success: true;
|
|
188
|
+
version: number;
|
|
189
|
+
}>;
|
|
190
|
+
connect(id: string, opts?: {
|
|
191
|
+
dynamicVariables?: DynamicVariables;
|
|
192
|
+
assistantOverride?: AssistantOverride;
|
|
193
|
+
agentVersion?: number;
|
|
194
|
+
metadata?: Record<string, unknown>;
|
|
195
|
+
}): Promise<{
|
|
196
|
+
roomName: string;
|
|
197
|
+
token: string;
|
|
198
|
+
livekitUrl: string;
|
|
199
|
+
callId: string;
|
|
200
|
+
}>;
|
|
201
|
+
}
|
|
202
|
+
declare class CallsResource {
|
|
203
|
+
private readonly http;
|
|
204
|
+
constructor(http: HttpClient);
|
|
205
|
+
list(): Promise<CallRecord[]>;
|
|
206
|
+
get(id: string): Promise<CallRecord>;
|
|
207
|
+
/**
|
|
208
|
+
* Place an outbound call. Optionally pass `idempotencyKey` so retries
|
|
209
|
+
* within 24h return the same response instead of placing a duplicate call.
|
|
210
|
+
*/
|
|
211
|
+
outbound(input: CallStartRequest, opts?: {
|
|
212
|
+
idempotencyKey?: string;
|
|
213
|
+
}): Promise<{
|
|
214
|
+
callId: string;
|
|
215
|
+
roomName: string;
|
|
216
|
+
}>;
|
|
217
|
+
end(id: string): Promise<{
|
|
218
|
+
success: true;
|
|
219
|
+
}>;
|
|
220
|
+
transfer(id: string, destination: string, summary?: string): Promise<{
|
|
221
|
+
success: true;
|
|
222
|
+
}>;
|
|
223
|
+
}
|
|
224
|
+
declare class PlatformResource {
|
|
225
|
+
private readonly http;
|
|
226
|
+
constructor(http: HttpClient);
|
|
227
|
+
/** Live platform constants — USD-to-INR rate and the minimum charge per call. */
|
|
228
|
+
getRates(): Promise<{
|
|
229
|
+
usdToInr: number;
|
|
230
|
+
minCallChargeInr: number;
|
|
231
|
+
}>;
|
|
232
|
+
/** Catalog of available LLM/STT/TTS providers + models. */
|
|
233
|
+
listProviders(): Promise<{
|
|
234
|
+
llm: Record<string, unknown>;
|
|
235
|
+
stt: Record<string, unknown>;
|
|
236
|
+
tts: Record<string, unknown>;
|
|
237
|
+
languages: Array<{
|
|
238
|
+
id: string;
|
|
239
|
+
name: string;
|
|
240
|
+
}>;
|
|
241
|
+
}>;
|
|
242
|
+
/**
|
|
243
|
+
* Quality presets (Fast / Balanced / Premium) with live per-minute
|
|
244
|
+
* cost estimates derived from the same rate tables we bill with.
|
|
245
|
+
* `costEstimate.{low, typical, high}` are INR per minute and account
|
|
246
|
+
* for typical 250 / 900 / 2500 prompt-token usage patterns.
|
|
247
|
+
*
|
|
248
|
+
* @param channel "phone" (default) includes SIP minutes; "web" or
|
|
249
|
+
* "chat" exclude SIP for cheaper web-only deployments.
|
|
250
|
+
*/
|
|
251
|
+
getPresets(channel?: "phone" | "whatsapp_call" | "web" | "chat"): Promise<{
|
|
252
|
+
global: Record<string, PresetWithCost>;
|
|
253
|
+
india: Record<string, PresetWithCost>;
|
|
254
|
+
}>;
|
|
255
|
+
/**
|
|
256
|
+
* Per-provider health snapshot. Cached server-side for 60s.
|
|
257
|
+
* Use this before launching a call to detect "sometimes works"
|
|
258
|
+
* provider issues (key revoked, region outage, ToS not accepted).
|
|
259
|
+
*/
|
|
260
|
+
getModelHealth(): Promise<Record<string, string | ProviderHealth>>;
|
|
261
|
+
/**
|
|
262
|
+
* Industry-organized agent templates (support, sales, healthcare,
|
|
263
|
+
* real-estate, etc.). When called with a valid session/API key, the
|
|
264
|
+
* response includes your org's custom-saved templates merged ahead
|
|
265
|
+
* of the built-ins; anonymous calls return built-ins only.
|
|
266
|
+
*/
|
|
267
|
+
getTemplates(params?: {
|
|
268
|
+
category?: string;
|
|
269
|
+
q?: string;
|
|
270
|
+
}): Promise<{
|
|
271
|
+
categories: Array<{
|
|
272
|
+
id: string;
|
|
273
|
+
label: string;
|
|
274
|
+
}>;
|
|
275
|
+
templates: AgentTemplateResult[];
|
|
276
|
+
}>;
|
|
277
|
+
getTemplate(id: string): Promise<AgentTemplateResult>;
|
|
278
|
+
/** Save a custom template (org-scoped, requires auth). */
|
|
279
|
+
saveTemplate(data: {
|
|
280
|
+
label: string;
|
|
281
|
+
name: string;
|
|
282
|
+
tagline?: string;
|
|
283
|
+
category?: string;
|
|
284
|
+
recommendedPreset?: "fast" | "balanced" | "premium";
|
|
285
|
+
tags?: string[];
|
|
286
|
+
systemPrompt: string;
|
|
287
|
+
welcomeMessage?: string;
|
|
288
|
+
}): Promise<AgentTemplateResult>;
|
|
289
|
+
deleteTemplate(id: string): Promise<{
|
|
290
|
+
success: boolean;
|
|
291
|
+
}>;
|
|
292
|
+
}
|
|
293
|
+
interface AgentTemplateResult {
|
|
294
|
+
id: string;
|
|
295
|
+
label: string;
|
|
296
|
+
category: string;
|
|
297
|
+
name: string;
|
|
298
|
+
tagline: string;
|
|
299
|
+
recommendedPreset: "fast" | "balanced" | "premium";
|
|
300
|
+
tags: string[];
|
|
301
|
+
systemPrompt: string;
|
|
302
|
+
welcomeMessage: string;
|
|
303
|
+
/** True when this is a custom template saved by the caller's org. */
|
|
304
|
+
isCustom?: boolean;
|
|
305
|
+
}
|
|
306
|
+
interface PresetCostEstimate {
|
|
307
|
+
/** INR per minute — light usage (FAQ, short prompts) */
|
|
308
|
+
low: number;
|
|
309
|
+
/** INR per minute — most agents land here */
|
|
310
|
+
typical: number;
|
|
311
|
+
/** INR per minute — verbose, large system prompt */
|
|
312
|
+
high: number;
|
|
313
|
+
currency: "INR";
|
|
314
|
+
/** Component-level breakdown for the typical scenario */
|
|
315
|
+
typicalBreakdown: {
|
|
316
|
+
llm: number;
|
|
317
|
+
stt: number;
|
|
318
|
+
tts: number;
|
|
319
|
+
sip: number;
|
|
320
|
+
platform: number;
|
|
321
|
+
total: number;
|
|
322
|
+
currency: "INR";
|
|
323
|
+
};
|
|
324
|
+
/** Whether SIP minutes were included */
|
|
325
|
+
includesSip: boolean;
|
|
326
|
+
}
|
|
327
|
+
interface PresetWithCost {
|
|
328
|
+
id: "fast" | "balanced" | "premium";
|
|
329
|
+
label: string;
|
|
330
|
+
description: string;
|
|
331
|
+
latencyMs: string;
|
|
332
|
+
llmProvider: string;
|
|
333
|
+
llmModel: string;
|
|
334
|
+
sttProvider: string;
|
|
335
|
+
sttModel: string;
|
|
336
|
+
ttsProvider: string;
|
|
337
|
+
ttsModel: string;
|
|
338
|
+
ttsVoice?: string;
|
|
339
|
+
costEstimate: PresetCostEstimate;
|
|
340
|
+
}
|
|
341
|
+
interface ProviderHealth {
|
|
342
|
+
status: "ok" | "degraded" | "down" | "unconfigured";
|
|
343
|
+
latencyMs: number | null;
|
|
344
|
+
error?: string;
|
|
345
|
+
}
|
|
346
|
+
/**
|
|
347
|
+
* Verify an osmTalk webhook signature.
|
|
348
|
+
*
|
|
349
|
+
* Pass the RAW request body (string or Buffer) — NOT the parsed JSON —
|
|
350
|
+
* along with the value of the `X-OsmTalk-Signature` header and the
|
|
351
|
+
* shared secret you configured under Settings → Webhook. Uses a
|
|
352
|
+
* constant-time comparison so attackers can't time-probe the signature.
|
|
353
|
+
*
|
|
354
|
+
* @example
|
|
355
|
+
* import { verifyWebhookSignature } from "@osmapi/osmtalk-sdk";
|
|
356
|
+
*
|
|
357
|
+
* app.post("/webhooks/osmtalk", async (req, res) => {
|
|
358
|
+
* const raw = await readRawBody(req); // do NOT use express.json() before this
|
|
359
|
+
* const sig = req.headers["x-osmtalk-signature"];
|
|
360
|
+
* if (!verifyWebhookSignature(raw, sig, process.env.OSMTALK_WEBHOOK_SECRET!)) {
|
|
361
|
+
* return res.status(401).end();
|
|
362
|
+
* }
|
|
363
|
+
* const payload = JSON.parse(raw);
|
|
364
|
+
* // ... handle payload
|
|
365
|
+
* res.status(200).end();
|
|
366
|
+
* });
|
|
367
|
+
*
|
|
368
|
+
* Works in Node 18+, Deno, Bun, and Cloudflare Workers (uses WebCrypto
|
|
369
|
+
* when `node:crypto` isn't available).
|
|
370
|
+
*/
|
|
371
|
+
declare function verifyWebhookSignature(rawBody: string | Uint8Array, signatureHeader: string | string[] | undefined, secret: string): boolean;
|
|
372
|
+
/** WebCrypto-based async variant for Deno / Bun / Workers. */
|
|
373
|
+
declare function verifyWebhookSignatureAsync(rawBody: string | Uint8Array, signatureHeader: string | string[] | undefined, secret: string): Promise<boolean>;
|
|
374
|
+
declare class CampaignsResource {
|
|
375
|
+
private readonly http;
|
|
376
|
+
constructor(http: HttpClient);
|
|
377
|
+
list(opts?: {
|
|
378
|
+
status?: string;
|
|
379
|
+
}): Promise<CampaignRecord[]>;
|
|
380
|
+
get(id: string): Promise<CampaignRecord>;
|
|
381
|
+
create(input: CampaignCreateRequest): Promise<CampaignRecord>;
|
|
382
|
+
update(id: string, input: Partial<CampaignCreateRequest>): Promise<{
|
|
383
|
+
success: true;
|
|
384
|
+
}>;
|
|
385
|
+
delete(id: string): Promise<{
|
|
386
|
+
success: true;
|
|
387
|
+
}>;
|
|
388
|
+
start(id: string): Promise<{
|
|
389
|
+
success: true;
|
|
390
|
+
status: string;
|
|
391
|
+
}>;
|
|
392
|
+
pause(id: string): Promise<{
|
|
393
|
+
success: true;
|
|
394
|
+
status: string;
|
|
395
|
+
}>;
|
|
396
|
+
resume(id: string): Promise<{
|
|
397
|
+
success: true;
|
|
398
|
+
status: string;
|
|
399
|
+
}>;
|
|
400
|
+
stop(id: string): Promise<{
|
|
401
|
+
success: true;
|
|
402
|
+
status: string;
|
|
403
|
+
}>;
|
|
404
|
+
report(id: string): Promise<{
|
|
405
|
+
campaign: CampaignRecord;
|
|
406
|
+
counts: {
|
|
407
|
+
byStatus: Record<string, number>;
|
|
408
|
+
byDisposition: Record<string, number>;
|
|
409
|
+
};
|
|
410
|
+
}>;
|
|
411
|
+
uploadLeadsCsv(id: string, csv: string): Promise<{
|
|
412
|
+
inserted: number;
|
|
413
|
+
csvErrors: string[];
|
|
414
|
+
}>;
|
|
415
|
+
uploadLeads(id: string, leads: LeadRow[]): Promise<{
|
|
416
|
+
inserted: number;
|
|
417
|
+
csvErrors: string[];
|
|
418
|
+
}>;
|
|
419
|
+
listLeads(id: string, opts?: {
|
|
420
|
+
status?: string;
|
|
421
|
+
limit?: number;
|
|
422
|
+
offset?: number;
|
|
423
|
+
}): Promise<Record<string, unknown>[]>;
|
|
424
|
+
}
|
|
425
|
+
declare class DncResource {
|
|
426
|
+
private readonly http;
|
|
427
|
+
constructor(http: HttpClient);
|
|
428
|
+
list(): Promise<Record<string, unknown>[]>;
|
|
429
|
+
add(phoneNumber: string, opts?: {
|
|
430
|
+
reason?: string;
|
|
431
|
+
source?: string;
|
|
432
|
+
notes?: string;
|
|
433
|
+
}): Promise<{
|
|
434
|
+
id: string;
|
|
435
|
+
}>;
|
|
436
|
+
bulkAdd(entries: Array<{
|
|
437
|
+
phoneNumber: string;
|
|
438
|
+
reason?: string;
|
|
439
|
+
source?: string;
|
|
440
|
+
notes?: string;
|
|
441
|
+
}>): Promise<{
|
|
442
|
+
inserted: number;
|
|
443
|
+
}>;
|
|
444
|
+
remove(id: string): Promise<{
|
|
445
|
+
success: true;
|
|
446
|
+
}>;
|
|
447
|
+
}
|
|
448
|
+
declare class EvalResource {
|
|
449
|
+
private readonly http;
|
|
450
|
+
constructor(http: HttpClient);
|
|
451
|
+
simulate(agentId: string, mockTurns: Array<{
|
|
452
|
+
role: "user" | "assistant";
|
|
453
|
+
content: string;
|
|
454
|
+
}>, opts?: {
|
|
455
|
+
dynamicVariables?: Record<string, string>;
|
|
456
|
+
agentVersion?: number;
|
|
457
|
+
}): Promise<{
|
|
458
|
+
transcript: Array<{
|
|
459
|
+
role: string;
|
|
460
|
+
content: string;
|
|
461
|
+
}>;
|
|
462
|
+
durationMs: number;
|
|
463
|
+
}>;
|
|
464
|
+
createTestCase(agentId: string, input: {
|
|
465
|
+
name: string;
|
|
466
|
+
description?: string;
|
|
467
|
+
mockTurns: Array<{
|
|
468
|
+
role: "user" | "assistant";
|
|
469
|
+
content: string;
|
|
470
|
+
}>;
|
|
471
|
+
expectedOutcome?: string;
|
|
472
|
+
judgePrompt?: string;
|
|
473
|
+
dynamicVariables?: Record<string, string>;
|
|
474
|
+
}): Promise<{
|
|
475
|
+
id: string;
|
|
476
|
+
}>;
|
|
477
|
+
listTestCases(agentId: string): Promise<Record<string, unknown>[]>;
|
|
478
|
+
runTestCase(agentId: string, testCaseId: string): Promise<Record<string, unknown>>;
|
|
479
|
+
runAll(agentId: string): Promise<{
|
|
480
|
+
runs: string[];
|
|
481
|
+
passed: number;
|
|
482
|
+
failed: number;
|
|
483
|
+
total: number;
|
|
484
|
+
}>;
|
|
485
|
+
listRuns(agentId: string): Promise<Record<string, unknown>[]>;
|
|
486
|
+
getRun(runId: string): Promise<Record<string, unknown>>;
|
|
487
|
+
}
|
|
488
|
+
declare class SettingsResource {
|
|
489
|
+
private readonly http;
|
|
490
|
+
constructor(http: HttpClient);
|
|
491
|
+
get(): Promise<Record<string, unknown>>;
|
|
492
|
+
getStorage(): Promise<Record<string, unknown>>;
|
|
493
|
+
updateStorage(input: Record<string, unknown>): Promise<Record<string, unknown>>;
|
|
494
|
+
getWebhook(): Promise<{
|
|
495
|
+
defaultWebhookUrl?: string | null;
|
|
496
|
+
defaultWebhookSecret?: string | null;
|
|
497
|
+
}>;
|
|
498
|
+
updateWebhook(input: {
|
|
499
|
+
defaultWebhookUrl?: string | null;
|
|
500
|
+
defaultWebhookSecret?: string | null;
|
|
501
|
+
}): Promise<{
|
|
502
|
+
success: true;
|
|
503
|
+
}>;
|
|
504
|
+
getCompliance(): Promise<Record<string, unknown>>;
|
|
505
|
+
updateCompliance(input: Record<string, unknown>): Promise<{
|
|
506
|
+
success: true;
|
|
507
|
+
}>;
|
|
508
|
+
}
|
|
509
|
+
declare class Osmtalk {
|
|
510
|
+
readonly agents: AgentsResource;
|
|
511
|
+
readonly calls: CallsResource;
|
|
512
|
+
readonly campaigns: CampaignsResource;
|
|
513
|
+
readonly dnc: DncResource;
|
|
514
|
+
readonly eval: EvalResource;
|
|
515
|
+
readonly settings: SettingsResource;
|
|
516
|
+
readonly platform: PlatformResource;
|
|
517
|
+
constructor(opts: OsmtalkOptions);
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
export { type AgentRecord, type AgentTemplateResult, type AssistantOverride, type CallRecord, type CallStartRequest, type CampaignCreateRequest, type CampaignRecord, type DynamicVariables, type LeadRow, Osmtalk, OsmtalkError, type OsmtalkErrorBody, type OsmtalkOptions, type PresetCostEstimate, type PresetWithCost, type ProviderHealth, Osmtalk as default, verifyWebhookSignature, verifyWebhookSignatureAsync };
|