@osmapi/osmtalk-sdk 0.3.0 → 0.4.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 CHANGED
@@ -2,11 +2,15 @@
2
2
 
3
3
  Official TypeScript / JavaScript SDK for the [osmTalk](https://osmtalk.com) voice AI platform.
4
4
 
5
+ [![npm](https://img.shields.io/npm/v/@osmapi/osmtalk-sdk.svg)](https://www.npmjs.com/package/@osmapi/osmtalk-sdk)
6
+
5
7
  ```bash
6
8
  npm install @osmapi/osmtalk-sdk
7
9
  # or: pnpm add @osmapi/osmtalk-sdk
8
10
  ```
9
11
 
12
+ Works in **Node 18+, Deno, Bun, Cloudflare Workers, and browsers**.
13
+
10
14
  ## Quick start
11
15
 
12
16
  ```ts
@@ -34,11 +38,32 @@ console.log("Call started:", call.callId);
34
38
  | Resource | Operations |
35
39
  |---|---|
36
40
  | `client.agents` | `list`, `get`, `create`, `update`, `delete`, `connect`, `publishVersion`, `listVersions`, `getVersion`, `rollbackToVersion` |
37
- | `client.calls` | `list`, `get`, `outbound`, `end`, `transfer` |
41
+ | `client.calls` | `list` (paginated), `get`, `outbound`, `end`, `transfer`, `waitUntilEnded` |
38
42
  | `client.campaigns` | `list`, `get`, `create`, `update`, `delete`, `start`, `pause`, `resume`, `stop`, `report`, `uploadLeadsCsv`, `uploadLeads`, `listLeads` |
43
+ | `client.phoneNumbers` | `list`, `update` |
39
44
  | `client.dnc` | `list`, `add`, `bulkAdd`, `remove` |
40
45
  | `client.eval` | `simulate`, `createTestCase`, `listTestCases`, `runTestCase`, `runAll`, `listRuns`, `getRun` |
41
46
  | `client.settings` | `get`, `getStorage`, `updateStorage`, `getWebhook`, `updateWebhook`, `getCompliance`, `updateCompliance` |
47
+ | `client.platform` | `getRates`, `listProviders`, `getPresets`, `getModelHealth`, `getTemplates`, `getTemplate`, `saveTemplate`, `deleteTemplate` |
48
+
49
+ Plus the standalone helpers `verifyWebhookSignature` / `verifyWebhookSignatureAsync` (see below).
50
+
51
+ ## What's new in 0.4.0
52
+
53
+ - **Breaking**: `client.calls.list()` now returns `Paginated<CallRecord>` — `{ data, total, limit, offset }` — not a raw array. The server always returned this shape; the prior type was wrong. See [CHANGELOG.md](./CHANGELOG.md) for a one-line migration.
54
+ - **New `client.phoneNumbers`** resource — `list()` and `update()` for managing org-owned numbers.
55
+ - **`calls.list()` accepts filters**: `status`, `agentId`, `channel`, `from`, `to`, `search`, `limit`, `offset`.
56
+
57
+ ## What's new in 0.3.0
58
+
59
+ - **Auto-retry** on 5xx, 429, and network errors with `Retry-After` honored and exponential backoff. No more hand-rolling retry wrappers.
60
+ - **`client.calls.waitUntilEnded(callId)`** — one-line polling helper for the "place call → wait → get result" pattern.
61
+ - **`AbortSignal`** support on every method via `RequestOptions.signal`.
62
+ - **`User-Agent`** header sent automatically.
63
+ - **Per-org request override** via `RequestOptions.organizationId`.
64
+ - **`OsmtalkError.isRetryable` / `.isClientError` / `.retryAttempts`** for cleaner error branching.
65
+
66
+ Full version history: [CHANGELOG.md](./CHANGELOG.md).
42
67
 
43
68
  ## Examples
44
69
 
@@ -68,6 +93,61 @@ const report = await client.campaigns.report(camp.id);
68
93
  console.log(report.counts.byStatus);
69
94
  ```
70
95
 
96
+ ### Listing recent calls with filters
97
+
98
+ ```ts
99
+ const { data, total } = await client.calls.list({
100
+ status: "completed",
101
+ channel: "phone",
102
+ from: "2026-05-01",
103
+ limit: 25,
104
+ });
105
+
106
+ console.log(`Showing ${data.length} of ${total} matching calls`);
107
+ for (const call of data) {
108
+ console.log(call.id, call.durationSeconds, "s", call.disposition);
109
+ }
110
+ ```
111
+
112
+ ### Wait for a call to finish (without writing a poll loop)
113
+
114
+ ```ts
115
+ const { callId } = await client.calls.outbound({
116
+ agentId: "agent_xxx",
117
+ phoneNumberId: "pn_xxx",
118
+ destination: "+919876543210",
119
+ });
120
+
121
+ // Default: poll every 5s, give up after 30 minutes. All configurable.
122
+ const final = await client.calls.waitUntilEnded(callId, {
123
+ pollIntervalMs: 5_000,
124
+ timeoutMs: 15 * 60 * 1000,
125
+ });
126
+
127
+ console.log("Final status:", final.status);
128
+ console.log("Duration: ", final.durationSeconds, "s");
129
+ console.log("Disposition: ", final.disposition);
130
+ console.log("Recording: ", final.recordingUrl);
131
+ ```
132
+
133
+ For production, prefer webhooks — see the receiver example below.
134
+
135
+ ### Cancel an in-flight request
136
+
137
+ ```ts
138
+ const ctrl = new AbortController();
139
+ setTimeout(() => ctrl.abort(), 2_000);
140
+
141
+ try {
142
+ await client.agents.list({ signal: ctrl.signal });
143
+ } catch (err) {
144
+ if (ctrl.signal.aborted) console.log("Cancelled by us");
145
+ else throw err;
146
+ }
147
+ ```
148
+
149
+ `signal`, `timeoutMs`, and `organizationId` are accepted on every method via the trailing `RequestOptions` argument.
150
+
71
151
  ### Publish a new agent version and A/B test
72
152
 
73
153
  ```ts
@@ -75,7 +155,12 @@ console.log(report.counts.byStatus);
75
155
  const v2 = await client.agents.publishVersion("agent_xxx", { label: "Tighter qualifier" });
76
156
 
77
157
  // Call with v2 explicitly
78
- await client.calls.outbound({ agentId: "agent_xxx", phoneNumberId: "pn_xxx", destination: "+919876543210", agentVersion: v2.version });
158
+ await client.calls.outbound({
159
+ agentId: "agent_xxx",
160
+ phoneNumberId: "pn_xxx",
161
+ destination: "+919876543210",
162
+ agentVersion: v2.version,
163
+ });
79
164
  ```
80
165
 
81
166
  ### Simulate before going live
@@ -91,33 +176,54 @@ for (const turn of sim.transcript) {
91
176
  }
92
177
  ```
93
178
 
94
- ### Handle the webhook in Node.js
179
+ ### Verify webhooks (Node, sync)
95
180
 
96
181
  ```ts
97
- import crypto from "node:crypto";
98
182
  import express from "express";
183
+ import { verifyWebhookSignature } from "@osmapi/osmtalk-sdk";
99
184
 
100
185
  const app = express();
101
- app.use(express.raw({ type: "application/json" }));
186
+ // IMPORTANT: use express.raw() NOT express.json(). The signature was
187
+ // computed over the exact bytes; re-serialized JSON will not match.
188
+ app.use("/webhooks/osmtalk", express.raw({ type: "application/json" }));
102
189
 
103
190
  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
- }
191
+ const ok = verifyWebhookSignature(
192
+ req.body,
193
+ req.header("x-osmtalk-signature"),
194
+ process.env.OSMTALK_WEBHOOK_SECRET!,
195
+ );
196
+ if (!ok) return res.status(401).end();
197
+
113
198
  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);
199
+ if (event.event === "call.completed") {
200
+ console.log("Call ended:", event.call.id, event.analysis?.disposition);
116
201
  }
117
202
  res.json({ ok: true });
118
203
  });
119
204
  ```
120
205
 
206
+ ### Verify webhooks in Workers / Deno / Bun (async, WebCrypto)
207
+
208
+ ```ts
209
+ import { verifyWebhookSignatureAsync } from "@osmapi/osmtalk-sdk";
210
+
211
+ export default {
212
+ async fetch(req: Request) {
213
+ const raw = await req.text();
214
+ const ok = await verifyWebhookSignatureAsync(
215
+ raw,
216
+ req.headers.get("x-osmtalk-signature"),
217
+ env.OSMTALK_WEBHOOK_SECRET,
218
+ );
219
+ if (!ok) return new Response("invalid signature", { status: 401 });
220
+ const event = JSON.parse(raw);
221
+ // …handle event
222
+ return new Response("ok");
223
+ },
224
+ };
225
+ ```
226
+
121
227
  ## Error handling
122
228
 
123
229
  ```ts
@@ -128,32 +234,61 @@ try {
128
234
  } catch (err) {
129
235
  if (err instanceof OsmtalkError) {
130
236
  console.log("HTTP", err.status, err.body);
237
+ console.log("Retries attempted:", err.retryAttempts);
238
+ if (err.isRetryable) console.log("Server might recover — try again later.");
239
+ if (err.isClientError) console.log("Bad input — check err.body.details.");
131
240
  } else {
132
241
  throw err;
133
242
  }
134
243
  }
135
244
  ```
136
245
 
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 |
246
+ | Status | Meaning | `OsmtalkError` flag |
247
+ |---|---|---|
248
+ | 400 | Validation — `err.body.details` has zod field errors | `isClientError` |
249
+ | 401 | Bad API key | `isClientError` |
250
+ | 402 | Insufficient credits | `isClientError` |
251
+ | 404 | Resource not found | `isClientError` |
252
+ | 408 | Request timeout | `isRetryable` |
253
+ | 429 | Concurrency or rate limit | `isRetryable` |
254
+ | 5xx | Server error / provider outage | `isRetryable` |
255
+
256
+ The SDK already auto-retries 408/429/5xx and network errors twice by default. Mutating requests (POST/PUT/DELETE) are only retried when you pass `idempotencyKey` so the SDK never silently double-charges.
145
257
 
146
258
  ## Options
147
259
 
148
260
  ```ts
149
261
  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)
262
+ apiKey: "osm_live_…",
263
+ baseUrl: "https://api.osmtalk.com", // default
264
+ timeoutMs: 30_000, // per-request, 0 to disable
265
+ maxRetries: 2, // auto-retry count for 5xx/429
266
+ retryInitialDelayMs: 250, // doubles per retry, jittered
267
+ organizationId: "org_xxx", // for multi-org accounts
268
+ defaultHeaders: { "X-Trace-Id": "…" },// added to every request
269
+ fetch: customFetch, // optional, defaults to global fetch
270
+ });
271
+ ```
272
+
273
+ Per-request overrides:
274
+
275
+ ```ts
276
+ await client.calls.outbound(input, {
277
+ idempotencyKey: `dest-${destination}-${date}`,
278
+ signal: controller.signal,
279
+ timeoutMs: 60_000,
280
+ organizationId: "org_yyy",
154
281
  });
155
282
  ```
156
283
 
284
+ ## Runnable examples
285
+
286
+ See [github.com/osm-API/osmtalk-examples](https://github.com/osm-API/osmtalk-examples) for three end-to-end projects:
287
+
288
+ 1. **Personalized outbound call** — dynamic per-user prompts
289
+ 2. **Bulk campaign from CSV** — scale to thousands
290
+ 3. **Verified webhook receiver** — close the loop with `verifyWebhookSignature`
291
+
157
292
  ## License
158
293
 
159
294
  MIT
package/dist/index.d.mts CHANGED
@@ -10,8 +10,24 @@
10
10
  * dynamicVariables: { first_name: "Arjun" },
11
11
  * });
12
12
  */
13
- /** Bumped on every release — surfaced in the User-Agent header. */
14
- declare const SDK_VERSION = "0.3.0";
13
+ /**
14
+ * Current SDK version, sent in the User-Agent header and useful for
15
+ * runtime version checks (e.g. logging which SDK build is talking to the
16
+ * API, or feature-detecting against minimum versions in shared code).
17
+ */
18
+ declare const SDK_VERSION = "0.4.0";
19
+ /**
20
+ * Paginated list envelope returned by some endpoints (currently
21
+ * `calls.list`; more list resources will migrate to this shape over
22
+ * future minor versions). Lets consumers build pagination UIs without
23
+ * a second count request.
24
+ */
25
+ interface Paginated<T> {
26
+ data: T[];
27
+ total: number;
28
+ limit: number;
29
+ offset: number;
30
+ }
15
31
  interface OsmtalkOptions {
16
32
  apiKey: string;
17
33
  baseUrl?: string;
@@ -41,8 +57,25 @@ interface OsmtalkOptions {
41
57
  */
42
58
  organizationId?: string;
43
59
  }
44
- interface RequestOptions {
45
- idempotencyKey?: string;
60
+ /** Extra options accepted by paginated list endpoints. */
61
+ interface ListOptions extends RequestOptionsBase {
62
+ limit?: number;
63
+ offset?: number;
64
+ }
65
+ /** Filters accepted by `client.calls.list()`. */
66
+ interface CallListOptions extends ListOptions {
67
+ status?: string;
68
+ agentId?: string;
69
+ channel?: "phone" | "web" | "chat" | "whatsapp_call" | "whatsapp_message" | (string & {});
70
+ /** ISO date (e.g. "2026-05-13"); filters by call started_at ≥ this date. */
71
+ from?: string;
72
+ /** ISO date; filters by call started_at on or before this date (end-of-day). */
73
+ to?: string;
74
+ /** Free-text search across room name + agent name. */
75
+ search?: string;
76
+ }
77
+ /** Internal base — RequestOptions adds idempotencyKey on top. */
78
+ interface RequestOptionsBase {
46
79
  /** AbortSignal for caller-side cancellation. Combined with the SDK's timeout signal. */
47
80
  signal?: AbortSignal;
48
81
  /** Per-call override of the global timeout. */
@@ -50,6 +83,9 @@ interface RequestOptions {
50
83
  /** Per-call override of the org ID. */
51
84
  organizationId?: string;
52
85
  }
86
+ interface RequestOptions extends RequestOptionsBase {
87
+ idempotencyKey?: string;
88
+ }
53
89
  interface DynamicVariables {
54
90
  [key: string]: string | number | boolean;
55
91
  }
@@ -253,12 +289,33 @@ declare class AgentsResource {
253
289
  callId: string;
254
290
  }>;
255
291
  }
256
- /** Call.status values that mean "no more state changes are coming". */
292
+ /**
293
+ * Call statuses that mean "no more state changes are coming" — the
294
+ * record is final and safe to consume. `waitUntilEnded()` polls until
295
+ * the call's status matches one of these.
296
+ *
297
+ * Exported so downstream code can mirror the SDK's definition of "done"
298
+ * without copy-pasting strings (e.g. when reacting to webhook events or
299
+ * filtering call lists in a dashboard).
300
+ */
257
301
  declare const TERMINAL_CALL_STATUSES: readonly ["completed", "failed", "ended", "cancelled"];
258
302
  declare class CallsResource {
259
303
  private readonly http;
260
304
  constructor(http: HttpClient);
261
- list(opts?: RequestOptions): Promise<CallRecord[]>;
305
+ /**
306
+ * List calls. Returns a paginated envelope (NOT a raw array) so you
307
+ * can drive UI pagination without a separate count query.
308
+ *
309
+ * const { data, total, limit, offset } = await client.calls.list({ limit: 50 });
310
+ *
311
+ * Filters supported: `status`, `agentId`, `channel`, `from`, `to`,
312
+ * `search`, plus standard `limit`/`offset`. See {@link CallListOptions}.
313
+ *
314
+ * Breaking change in SDK 0.4.0: prior versions typed this as
315
+ * `Promise<CallRecord[]>` but the server has always returned an
316
+ * envelope. The type now matches reality.
317
+ */
318
+ list(opts?: CallListOptions): Promise<Paginated<CallRecord>>;
262
319
  get(id: string, opts?: RequestOptions): Promise<CallRecord>;
263
320
  /**
264
321
  * Place an outbound call. Pass `idempotencyKey` so a retry within 24h
@@ -495,6 +552,36 @@ declare class CampaignsResource {
495
552
  offset?: number;
496
553
  }): Promise<Record<string, unknown>[]>;
497
554
  }
555
+ interface PhoneNumberRecord {
556
+ id: string;
557
+ phoneNumber: string;
558
+ name?: string | null;
559
+ countryCode?: string | null;
560
+ inboundAgentId?: string | null;
561
+ outboundAgentId?: string | null;
562
+ /** Joined from the agents table; convenience when rendering UIs. */
563
+ inboundAgentName?: string | null;
564
+ sipProvider?: string | null;
565
+ monthlyRental?: string | null;
566
+ isActive: boolean;
567
+ createdAt?: string | null;
568
+ [key: string]: unknown;
569
+ }
570
+ declare class PhoneNumbersResource {
571
+ private readonly http;
572
+ constructor(http: HttpClient);
573
+ /**
574
+ * List phone numbers owned by your org.
575
+ * Returns a plain array (not yet paginated server-side).
576
+ */
577
+ list(opts?: RequestOptions): Promise<PhoneNumberRecord[]>;
578
+ /** Update the friendly name and/or agent bindings on a number. */
579
+ update(id: string, input: {
580
+ name?: string;
581
+ inboundAgentId?: string | null;
582
+ outboundAgentId?: string | null;
583
+ }, opts?: RequestOptions): Promise<PhoneNumberRecord>;
584
+ }
498
585
  declare class DncResource {
499
586
  private readonly http;
500
587
  constructor(http: HttpClient);
@@ -583,6 +670,7 @@ declare class Osmtalk {
583
670
  readonly agents: AgentsResource;
584
671
  readonly calls: CallsResource;
585
672
  readonly campaigns: CampaignsResource;
673
+ readonly phoneNumbers: PhoneNumbersResource;
586
674
  readonly dnc: DncResource;
587
675
  readonly eval: EvalResource;
588
676
  readonly settings: SettingsResource;
@@ -590,4 +678,4 @@ declare class Osmtalk {
590
678
  constructor(opts: OsmtalkOptions);
591
679
  }
592
680
 
593
- 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, type RequestOptions, SDK_VERSION, TERMINAL_CALL_STATUSES, Osmtalk as default, verifyWebhookSignature, verifyWebhookSignatureAsync };
681
+ export { type AgentRecord, type AgentTemplateResult, type AssistantOverride, type CallListOptions, type CallRecord, type CallStartRequest, type CampaignCreateRequest, type CampaignRecord, type DynamicVariables, type LeadRow, type ListOptions, Osmtalk, OsmtalkError, type OsmtalkErrorBody, type OsmtalkOptions, type Paginated, type PhoneNumberRecord, type PresetCostEstimate, type PresetWithCost, type ProviderHealth, type RequestOptions, SDK_VERSION, TERMINAL_CALL_STATUSES, Osmtalk as default, verifyWebhookSignature, verifyWebhookSignatureAsync };
package/dist/index.d.ts CHANGED
@@ -10,8 +10,24 @@
10
10
  * dynamicVariables: { first_name: "Arjun" },
11
11
  * });
12
12
  */
13
- /** Bumped on every release — surfaced in the User-Agent header. */
14
- declare const SDK_VERSION = "0.3.0";
13
+ /**
14
+ * Current SDK version, sent in the User-Agent header and useful for
15
+ * runtime version checks (e.g. logging which SDK build is talking to the
16
+ * API, or feature-detecting against minimum versions in shared code).
17
+ */
18
+ declare const SDK_VERSION = "0.4.0";
19
+ /**
20
+ * Paginated list envelope returned by some endpoints (currently
21
+ * `calls.list`; more list resources will migrate to this shape over
22
+ * future minor versions). Lets consumers build pagination UIs without
23
+ * a second count request.
24
+ */
25
+ interface Paginated<T> {
26
+ data: T[];
27
+ total: number;
28
+ limit: number;
29
+ offset: number;
30
+ }
15
31
  interface OsmtalkOptions {
16
32
  apiKey: string;
17
33
  baseUrl?: string;
@@ -41,8 +57,25 @@ interface OsmtalkOptions {
41
57
  */
42
58
  organizationId?: string;
43
59
  }
44
- interface RequestOptions {
45
- idempotencyKey?: string;
60
+ /** Extra options accepted by paginated list endpoints. */
61
+ interface ListOptions extends RequestOptionsBase {
62
+ limit?: number;
63
+ offset?: number;
64
+ }
65
+ /** Filters accepted by `client.calls.list()`. */
66
+ interface CallListOptions extends ListOptions {
67
+ status?: string;
68
+ agentId?: string;
69
+ channel?: "phone" | "web" | "chat" | "whatsapp_call" | "whatsapp_message" | (string & {});
70
+ /** ISO date (e.g. "2026-05-13"); filters by call started_at ≥ this date. */
71
+ from?: string;
72
+ /** ISO date; filters by call started_at on or before this date (end-of-day). */
73
+ to?: string;
74
+ /** Free-text search across room name + agent name. */
75
+ search?: string;
76
+ }
77
+ /** Internal base — RequestOptions adds idempotencyKey on top. */
78
+ interface RequestOptionsBase {
46
79
  /** AbortSignal for caller-side cancellation. Combined with the SDK's timeout signal. */
47
80
  signal?: AbortSignal;
48
81
  /** Per-call override of the global timeout. */
@@ -50,6 +83,9 @@ interface RequestOptions {
50
83
  /** Per-call override of the org ID. */
51
84
  organizationId?: string;
52
85
  }
86
+ interface RequestOptions extends RequestOptionsBase {
87
+ idempotencyKey?: string;
88
+ }
53
89
  interface DynamicVariables {
54
90
  [key: string]: string | number | boolean;
55
91
  }
@@ -253,12 +289,33 @@ declare class AgentsResource {
253
289
  callId: string;
254
290
  }>;
255
291
  }
256
- /** Call.status values that mean "no more state changes are coming". */
292
+ /**
293
+ * Call statuses that mean "no more state changes are coming" — the
294
+ * record is final and safe to consume. `waitUntilEnded()` polls until
295
+ * the call's status matches one of these.
296
+ *
297
+ * Exported so downstream code can mirror the SDK's definition of "done"
298
+ * without copy-pasting strings (e.g. when reacting to webhook events or
299
+ * filtering call lists in a dashboard).
300
+ */
257
301
  declare const TERMINAL_CALL_STATUSES: readonly ["completed", "failed", "ended", "cancelled"];
258
302
  declare class CallsResource {
259
303
  private readonly http;
260
304
  constructor(http: HttpClient);
261
- list(opts?: RequestOptions): Promise<CallRecord[]>;
305
+ /**
306
+ * List calls. Returns a paginated envelope (NOT a raw array) so you
307
+ * can drive UI pagination without a separate count query.
308
+ *
309
+ * const { data, total, limit, offset } = await client.calls.list({ limit: 50 });
310
+ *
311
+ * Filters supported: `status`, `agentId`, `channel`, `from`, `to`,
312
+ * `search`, plus standard `limit`/`offset`. See {@link CallListOptions}.
313
+ *
314
+ * Breaking change in SDK 0.4.0: prior versions typed this as
315
+ * `Promise<CallRecord[]>` but the server has always returned an
316
+ * envelope. The type now matches reality.
317
+ */
318
+ list(opts?: CallListOptions): Promise<Paginated<CallRecord>>;
262
319
  get(id: string, opts?: RequestOptions): Promise<CallRecord>;
263
320
  /**
264
321
  * Place an outbound call. Pass `idempotencyKey` so a retry within 24h
@@ -495,6 +552,36 @@ declare class CampaignsResource {
495
552
  offset?: number;
496
553
  }): Promise<Record<string, unknown>[]>;
497
554
  }
555
+ interface PhoneNumberRecord {
556
+ id: string;
557
+ phoneNumber: string;
558
+ name?: string | null;
559
+ countryCode?: string | null;
560
+ inboundAgentId?: string | null;
561
+ outboundAgentId?: string | null;
562
+ /** Joined from the agents table; convenience when rendering UIs. */
563
+ inboundAgentName?: string | null;
564
+ sipProvider?: string | null;
565
+ monthlyRental?: string | null;
566
+ isActive: boolean;
567
+ createdAt?: string | null;
568
+ [key: string]: unknown;
569
+ }
570
+ declare class PhoneNumbersResource {
571
+ private readonly http;
572
+ constructor(http: HttpClient);
573
+ /**
574
+ * List phone numbers owned by your org.
575
+ * Returns a plain array (not yet paginated server-side).
576
+ */
577
+ list(opts?: RequestOptions): Promise<PhoneNumberRecord[]>;
578
+ /** Update the friendly name and/or agent bindings on a number. */
579
+ update(id: string, input: {
580
+ name?: string;
581
+ inboundAgentId?: string | null;
582
+ outboundAgentId?: string | null;
583
+ }, opts?: RequestOptions): Promise<PhoneNumberRecord>;
584
+ }
498
585
  declare class DncResource {
499
586
  private readonly http;
500
587
  constructor(http: HttpClient);
@@ -583,6 +670,7 @@ declare class Osmtalk {
583
670
  readonly agents: AgentsResource;
584
671
  readonly calls: CallsResource;
585
672
  readonly campaigns: CampaignsResource;
673
+ readonly phoneNumbers: PhoneNumbersResource;
586
674
  readonly dnc: DncResource;
587
675
  readonly eval: EvalResource;
588
676
  readonly settings: SettingsResource;
@@ -590,4 +678,4 @@ declare class Osmtalk {
590
678
  constructor(opts: OsmtalkOptions);
591
679
  }
592
680
 
593
- 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, type RequestOptions, SDK_VERSION, TERMINAL_CALL_STATUSES, Osmtalk as default, verifyWebhookSignature, verifyWebhookSignatureAsync };
681
+ export { type AgentRecord, type AgentTemplateResult, type AssistantOverride, type CallListOptions, type CallRecord, type CallStartRequest, type CampaignCreateRequest, type CampaignRecord, type DynamicVariables, type LeadRow, type ListOptions, Osmtalk, OsmtalkError, type OsmtalkErrorBody, type OsmtalkOptions, type Paginated, type PhoneNumberRecord, type PresetCostEstimate, type PresetWithCost, type ProviderHealth, type RequestOptions, SDK_VERSION, TERMINAL_CALL_STATUSES, Osmtalk as default, verifyWebhookSignature, verifyWebhookSignatureAsync };
package/dist/index.js CHANGED
@@ -29,7 +29,7 @@ __export(index_exports, {
29
29
  verifyWebhookSignatureAsync: () => verifyWebhookSignatureAsync
30
30
  });
31
31
  module.exports = __toCommonJS(index_exports);
32
- var SDK_VERSION = "0.3.0";
32
+ var SDK_VERSION = "0.4.0";
33
33
  var OsmtalkError = class extends Error {
34
34
  status;
35
35
  body;
@@ -273,8 +273,38 @@ var CallsResource = class {
273
273
  this.http = http;
274
274
  }
275
275
  http;
276
+ /**
277
+ * List calls. Returns a paginated envelope (NOT a raw array) so you
278
+ * can drive UI pagination without a separate count query.
279
+ *
280
+ * const { data, total, limit, offset } = await client.calls.list({ limit: 50 });
281
+ *
282
+ * Filters supported: `status`, `agentId`, `channel`, `from`, `to`,
283
+ * `search`, plus standard `limit`/`offset`. See {@link CallListOptions}.
284
+ *
285
+ * Breaking change in SDK 0.4.0: prior versions typed this as
286
+ * `Promise<CallRecord[]>` but the server has always returned an
287
+ * envelope. The type now matches reality.
288
+ */
276
289
  list(opts) {
277
- return this.http.request("GET", "/api/calls", void 0, void 0, void 0, opts);
290
+ const qs = new URLSearchParams();
291
+ if (opts?.status) qs.set("status", opts.status);
292
+ if (opts?.agentId) qs.set("agentId", opts.agentId);
293
+ if (opts?.channel) qs.set("channel", String(opts.channel));
294
+ if (opts?.from) qs.set("from", opts.from);
295
+ if (opts?.to) qs.set("to", opts.to);
296
+ if (opts?.search) qs.set("search", opts.search);
297
+ if (opts?.limit !== void 0) qs.set("limit", String(opts.limit));
298
+ if (opts?.offset !== void 0) qs.set("offset", String(opts.offset));
299
+ const suffix = qs.toString() ? `?${qs}` : "";
300
+ return this.http.request(
301
+ "GET",
302
+ `/api/calls${suffix}`,
303
+ void 0,
304
+ void 0,
305
+ void 0,
306
+ opts
307
+ );
278
308
  }
279
309
  get(id, opts) {
280
310
  return this.http.request("GET", `/api/calls/${id}`, void 0, void 0, void 0, opts);
@@ -519,6 +549,37 @@ var CampaignsResource = class {
519
549
  return this.http.request("GET", `/api/campaigns/${id}/leads${suffix}`);
520
550
  }
521
551
  };
552
+ var PhoneNumbersResource = class {
553
+ constructor(http) {
554
+ this.http = http;
555
+ }
556
+ http;
557
+ /**
558
+ * List phone numbers owned by your org.
559
+ * Returns a plain array (not yet paginated server-side).
560
+ */
561
+ list(opts) {
562
+ return this.http.request(
563
+ "GET",
564
+ "/api/phone-numbers",
565
+ void 0,
566
+ void 0,
567
+ void 0,
568
+ opts
569
+ );
570
+ }
571
+ /** Update the friendly name and/or agent bindings on a number. */
572
+ update(id, input, opts) {
573
+ return this.http.request(
574
+ "PUT",
575
+ `/api/phone-numbers/${id}`,
576
+ input,
577
+ void 0,
578
+ opts?.idempotencyKey,
579
+ opts
580
+ );
581
+ }
582
+ };
522
583
  var DncResource = class {
523
584
  constructor(http) {
524
585
  this.http = http;
@@ -602,6 +663,7 @@ var Osmtalk = class {
602
663
  agents;
603
664
  calls;
604
665
  campaigns;
666
+ phoneNumbers;
605
667
  dnc;
606
668
  eval;
607
669
  settings;
@@ -611,6 +673,7 @@ var Osmtalk = class {
611
673
  this.agents = new AgentsResource(http);
612
674
  this.calls = new CallsResource(http);
613
675
  this.campaigns = new CampaignsResource(http);
676
+ this.phoneNumbers = new PhoneNumbersResource(http);
614
677
  this.dnc = new DncResource(http);
615
678
  this.eval = new EvalResource(http);
616
679
  this.settings = new SettingsResource(http);
package/dist/index.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  // src/index.ts
2
- var SDK_VERSION = "0.3.0";
2
+ var SDK_VERSION = "0.4.0";
3
3
  var OsmtalkError = class extends Error {
4
4
  status;
5
5
  body;
@@ -243,8 +243,38 @@ var CallsResource = class {
243
243
  this.http = http;
244
244
  }
245
245
  http;
246
+ /**
247
+ * List calls. Returns a paginated envelope (NOT a raw array) so you
248
+ * can drive UI pagination without a separate count query.
249
+ *
250
+ * const { data, total, limit, offset } = await client.calls.list({ limit: 50 });
251
+ *
252
+ * Filters supported: `status`, `agentId`, `channel`, `from`, `to`,
253
+ * `search`, plus standard `limit`/`offset`. See {@link CallListOptions}.
254
+ *
255
+ * Breaking change in SDK 0.4.0: prior versions typed this as
256
+ * `Promise<CallRecord[]>` but the server has always returned an
257
+ * envelope. The type now matches reality.
258
+ */
246
259
  list(opts) {
247
- return this.http.request("GET", "/api/calls", void 0, void 0, void 0, opts);
260
+ const qs = new URLSearchParams();
261
+ if (opts?.status) qs.set("status", opts.status);
262
+ if (opts?.agentId) qs.set("agentId", opts.agentId);
263
+ if (opts?.channel) qs.set("channel", String(opts.channel));
264
+ if (opts?.from) qs.set("from", opts.from);
265
+ if (opts?.to) qs.set("to", opts.to);
266
+ if (opts?.search) qs.set("search", opts.search);
267
+ if (opts?.limit !== void 0) qs.set("limit", String(opts.limit));
268
+ if (opts?.offset !== void 0) qs.set("offset", String(opts.offset));
269
+ const suffix = qs.toString() ? `?${qs}` : "";
270
+ return this.http.request(
271
+ "GET",
272
+ `/api/calls${suffix}`,
273
+ void 0,
274
+ void 0,
275
+ void 0,
276
+ opts
277
+ );
248
278
  }
249
279
  get(id, opts) {
250
280
  return this.http.request("GET", `/api/calls/${id}`, void 0, void 0, void 0, opts);
@@ -489,6 +519,37 @@ var CampaignsResource = class {
489
519
  return this.http.request("GET", `/api/campaigns/${id}/leads${suffix}`);
490
520
  }
491
521
  };
522
+ var PhoneNumbersResource = class {
523
+ constructor(http) {
524
+ this.http = http;
525
+ }
526
+ http;
527
+ /**
528
+ * List phone numbers owned by your org.
529
+ * Returns a plain array (not yet paginated server-side).
530
+ */
531
+ list(opts) {
532
+ return this.http.request(
533
+ "GET",
534
+ "/api/phone-numbers",
535
+ void 0,
536
+ void 0,
537
+ void 0,
538
+ opts
539
+ );
540
+ }
541
+ /** Update the friendly name and/or agent bindings on a number. */
542
+ update(id, input, opts) {
543
+ return this.http.request(
544
+ "PUT",
545
+ `/api/phone-numbers/${id}`,
546
+ input,
547
+ void 0,
548
+ opts?.idempotencyKey,
549
+ opts
550
+ );
551
+ }
552
+ };
492
553
  var DncResource = class {
493
554
  constructor(http) {
494
555
  this.http = http;
@@ -572,6 +633,7 @@ var Osmtalk = class {
572
633
  agents;
573
634
  calls;
574
635
  campaigns;
636
+ phoneNumbers;
575
637
  dnc;
576
638
  eval;
577
639
  settings;
@@ -581,6 +643,7 @@ var Osmtalk = class {
581
643
  this.agents = new AgentsResource(http);
582
644
  this.calls = new CallsResource(http);
583
645
  this.campaigns = new CampaignsResource(http);
646
+ this.phoneNumbers = new PhoneNumbersResource(http);
584
647
  this.dnc = new DncResource(http);
585
648
  this.eval = new EvalResource(http);
586
649
  this.settings = new SettingsResource(http);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osmapi/osmtalk-sdk",
3
- "version": "0.3.0",
3
+ "version": "0.4.0",
4
4
  "description": "Official TypeScript SDK for the osmTalk voice AI platform",
5
5
  "homepage": "https://docs.osmtalk.com",
6
6
  "repository": {