@cemscale-voip/voip-sdk 2.0.11 → 2.0.12

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/dist/types.d.ts CHANGED
@@ -1,30 +1,108 @@
1
+ /**
2
+ * Parameters for logging in as an extension user (softphone / SDK consumer).
3
+ *
4
+ * Extensions authenticate with their extension number + password, scoped to a tenant.
5
+ * After login you receive a JWT token valid for the tenant.
6
+ *
7
+ * @example
8
+ * ```ts
9
+ * const { token, user } = await voip.login({
10
+ * username: '1001',
11
+ * password: 'my-sip-password',
12
+ * tenantId: 'uuid-of-tenant',
13
+ * });
14
+ * ```
15
+ */
1
16
  export interface LoginParams {
17
+ /** Extension number (e.g. `"1001"`, `"2005"`). 3-6 digit identifier within a tenant. */
2
18
  username: string;
19
+ /** SIP password set on the extension. Case-sensitive, min 6 characters. */
3
20
  password: string;
21
+ /** UUID of the tenant this extension belongs to. Obtain this from the dashboard or from the list of tenants. */
4
22
  tenantId: string;
5
23
  }
24
+ /**
25
+ * Parameters for logging in as a tenant admin (dashboard user).
26
+ *
27
+ * Tenant admins authenticate with email + password and get a JWT that allows
28
+ * management of their own tenant's resources (extensions, DIDs, queues, etc.).
29
+ *
30
+ * @example
31
+ * ```ts
32
+ * const { token, tenant } = await voip.adminLogin({
33
+ * email: 'admin@acme.com',
34
+ * password: 'admin-password',
35
+ * });
36
+ * ```
37
+ */
6
38
  export interface AdminLoginParams {
39
+ /** Admin email address for the tenant (set during tenant creation). */
7
40
  email: string;
41
+ /** Admin password for the tenant admin account. */
8
42
  password: string;
9
43
  }
44
+ /**
45
+ * Response from both `login()` (extension) and `adminLogin()` (admin).
46
+ *
47
+ * Always contains a JWT `token`. The SDK stores this internally and attaches it
48
+ * to subsequent requests as `Authorization: Bearer <token>`.
49
+ *
50
+ * For extension login, `user` is populated with the extension profile.
51
+ * For admin login, `tenant` is populated. Global superadmin login populates both.
52
+ */
10
53
  export interface AuthResponse {
54
+ /** JWT token (HS256). Store this and pass it to the SDK constructor or set on the client. Expires based on server config (default 24h). */
11
55
  token: string;
56
+ /** Extension profile — populated when logging in as an extension user. Null for admin logins. */
12
57
  user?: {
58
+ /** Extension UUID in the database (not the extension number). */
13
59
  id: string;
60
+ /** Extension number string (e.g. `"1001"`). */
14
61
  extension: string;
62
+ /** Human-readable display name. `null` if not set on the extension. */
15
63
  displayName: string | null;
64
+ /** UUID of the tenant this extension belongs to. */
16
65
  tenantId: string;
17
66
  };
67
+ /** Tenant info — populated when logging in as an admin or superadmin. Null for extension-only logins. */
18
68
  tenant?: {
69
+ /** Tenant UUID. */
19
70
  id: string;
71
+ /** Subdomain slug (e.g. `"acme"`). Used in URLs like `acme.demo.cemscale.com`. */
20
72
  subdomain: string;
73
+ /** Company/tenant display name (e.g. `"Acme Corp"`). */
21
74
  companyName: string;
22
75
  };
23
76
  }
77
+ /**
78
+ * TURN/STUN credentials for WebRTC ICE negotiation.
79
+ *
80
+ * The TURN server relays media when a direct peer-to-peer connection can't be
81
+ * established (NAT, firewall). These credentials are time-limited (default 86400s).
82
+ *
83
+ * Retrieve via `getTurnCredentials()`. Pass to the WebRTCPhone constructor.
84
+ *
85
+ * @example
86
+ * ```ts
87
+ * const creds = await voip.getTurnCredentials();
88
+ * const phone = new WebRTCPhone({
89
+ * ...sipConfig,
90
+ * turnServers: [{
91
+ * urls: creds.urls,
92
+ * username: creds.username,
93
+ * credential: creds.credential,
94
+ * }],
95
+ * });
96
+ * ```
97
+ */
24
98
  export interface TurnCredentials {
99
+ /** TURN server URLs (e.g. `["turn:3.20.219.41:3478?transport=udp", "turns:3.20.219.41:5349?transport=tcp"]`). */
25
100
  urls: string[];
101
+ /** Temporary TURN username generated for this session. Format: `<expiry_timestamp>:<extension>`. */
26
102
  username: string;
103
+ /** HMAC-SHA1 credential derived from the TURN secret + username. Valid only until expiry. */
27
104
  credential: string;
105
+ /** Time-to-live in seconds (default 86400 = 24 hours). Credentials expire after this. */
28
106
  ttl: number;
29
107
  }
30
108
  /**
@@ -77,20 +155,31 @@ export interface TurnCredentials {
77
155
  * database, send them in emails, or cache them indefinitely.
78
156
  */
79
157
  export interface CallRecord {
158
+ /** Database record UUID. Use this for `getCall(id)`, `getRecordingUrl(id)`, and the recording audio endpoint `/api/recordings/<id>/audio`. Distinguish from `call_uuid` which is the FreeSWITCH-level identifier. */
80
159
  id: string;
160
+ /** Tenant UUID the call belongs to. Present for tenant-scoped queries; may be absent if querying as superadmin across all tenants. */
81
161
  tenant_id?: string;
162
+ /** FreeSWITCH call UUID. This is the server-side channel identifier used in FreeSWITCH commands (e.g. `uuid_kill`). Different from `id` (the DB record UUID). Use `call_uuid` for live call operations, `id` for API/CDR lookups. Example: `"a1b2c3d4-e5f6-7890-abcd-ef1234567890"`. */
82
163
  call_uuid: string;
164
+ /** Direction of the call relative to the tenant: `'inbound'` (PSTN → extension), `'outbound'` (extension → PSTN), `'internal'` (extension → extension within same tenant). */
83
165
  direction: 'inbound' | 'outbound' | 'internal';
166
+ /** Display name from the caller's SIP header. `null` if not provided by the carrier. Example: `"John Doe"`. */
84
167
  caller_id_name: string | null;
168
+ /** E.164 caller phone number. `null` if the caller number was hidden/unknown. Example: `"+17865551234"`. */
85
169
  caller_id_number: string | null;
170
+ /** Destination of the call. For inbound calls this is the DID or extension DNIS. For outbound calls this is the dialed PSTN number. `null` for some internal calls. Example: `"+17869876543"` or `"1001"`. */
86
171
  destination: string | null;
172
+ /** Call outcome: `'completed'` (answered + hung up normally), `'failed'` (never connected), `'missed'` (rang but not answered), `'voicemail'` (went to voicemail). `null` for in-progress or unknown state. */
87
173
  status: string | null;
174
+ /** FreeSWITCH hangup cause code string (e.g. `"NORMAL_CLEARING"`, `"NO_ANSWER"`, `"USER_BUSY"`). `null` if the call hasn't ended. */
88
175
  hangup_cause: string | null;
176
+ /** Total call duration in seconds from start to end. `null` for active/unfinished calls. */
89
177
  duration_seconds: number | null;
178
+ /** Billable seconds — from answer to hangup. `null` if call was never answered. Always ≤ `duration_seconds`. */
90
179
  billsec: number | null;
91
- /** External number the call was forwarded to. Null if no forwarding occurred. */
180
+ /** External number the call was forwarded to. Null if no forwarding occurred. Example: `"+13051234567"`. */
92
181
  forwarded_to?: string | null;
93
- /** Whether a voicemail message was left by the caller */
182
+ /** Whether a voicemail message was left by the caller. `true` = voicemail left, `false` or `null` = no voicemail. */
94
183
  was_voicemail?: boolean | null;
95
184
  /**
96
185
  * API endpoint URL for streaming/downloading the call recording.
@@ -138,42 +227,81 @@ export interface CallRecord {
138
227
  * ```
139
228
  */
140
229
  cdn_url: string | null;
230
+ /** ISO 8601 timestamp when the call was initiated. `null` for pre-CDR records. Example: `"2025-06-04T14:30:00.000Z"`. */
141
231
  started_at: string | null;
232
+ /** ISO 8601 timestamp when the call was answered (picked up). `null` if never answered. Example: `"2025-06-04T14:30:05.000Z"`. */
142
233
  answered_at: string | null;
234
+ /** ISO 8601 timestamp when the call ended (hung up). `null` for active calls. Example: `"2025-06-04T14:32:30.000Z"`. */
143
235
  ended_at: string | null;
236
+ /** Arbitrary key-value metadata attached to the call. `null` if no metadata was set. */
144
237
  metadata?: Record<string, unknown> | null;
145
- /** Present when queried as global superadmin */
238
+ /** Present when queried as global superadmin — contains tenant details for this call. */
146
239
  tenants?: TenantInfo;
147
- /** Present when queried as global superadmin (convenience top-level fields) */
240
+ /** Present when queried as global superadmin (convenience top-level fields). Tenant company name. */
148
241
  company_name?: string;
242
+ /** Present when queried as global superadmin (convenience top-level fields). Tenant subdomain. */
149
243
  subdomain?: string;
150
244
  }
245
+ /**
246
+ * Standard pagination metadata returned by all list endpoints.
247
+ *
248
+ * Use `pages` to render page controls and `total` for summary text.
249
+ * On the last page, `page` === `pages`.
250
+ */
151
251
  export interface PaginationInfo {
252
+ /** Current page number (1-indexed). Example: `1`. */
152
253
  page: number;
254
+ /** Number of items per page as requested. Example: `50`. */
153
255
  limit: number;
256
+ /** Total number of items across all pages. Example: `142`. */
154
257
  total: number;
258
+ /** Total number of pages. Example: `3`. Computed as `Math.ceil(total / limit)`. */
155
259
  pages: number;
156
260
  }
261
+ /**
262
+ * Response from `listCalls()` — a paginated list of call detail records.
263
+ *
264
+ * Use `pagination.total` for a summary badge and `pagination.pages` for pagination controls.
265
+ */
157
266
  export interface CallListResponse {
158
267
  calls: CallRecord[];
159
268
  pagination: PaginationInfo;
160
269
  }
270
+ /**
271
+ * Filtering/pagination params for `listCalls()`.
272
+ *
273
+ * All fields are optional. Omitted fields are not filtered (returns all matching records).
274
+ * Combine filters: `{ direction: 'inbound', status: 'completed', dateFrom: '2025-06-01' }`
275
+ * returns only completed inbound calls since June 1.
276
+ *
277
+ * @example
278
+ * ```ts
279
+ * // Get last 10 missed inbound calls
280
+ * const { calls } = await voip.listCalls({
281
+ * direction: 'inbound',
282
+ * status: 'missed',
283
+ * limit: 10,
284
+ * });
285
+ * ```
286
+ */
161
287
  export interface CallListParams {
288
+ /** Page number (1-indexed). Default: `1`. */
162
289
  page?: number;
163
- /** Max 500 per page */
290
+ /** Max 500 per page. Default: `50`. */
164
291
  limit?: number;
292
+ /** Filter by call direction. Default: `'all'` (no filter). */
165
293
  direction?: 'inbound' | 'outbound' | 'internal' | 'all';
166
- /** Filter by call status */
294
+ /** Filter by call status. Default: `'all'` (no filter). */
167
295
  status?: 'completed' | 'failed' | 'missed' | 'voicemail' | 'all';
168
- /** ISO date string — calls started on or after this date */
296
+ /** ISO date string — calls started on or after this date. Example: `"2025-06-01T00:00:00.000Z"`. */
169
297
  dateFrom?: string;
170
- /** ISO date string — calls started on or before this date */
298
+ /** ISO date string — calls started on or before this date. Example: `"2025-06-04T23:59:59.999Z"`. */
171
299
  dateTo?: string;
172
- /** Filter by extension number (matches caller or destination) */
300
+ /** Filter by extension number (matches caller or destination). Example: `"1001"`. */
173
301
  extension?: string;
174
- /** Search by phone number or name (matches caller_id_number, destination, caller_id_name) */
302
+ /** Search by phone number or name (matches caller_id_number, destination, caller_id_name). Partial match, case-insensitive. Example: `"+1786"`. */
175
303
  number?: string;
176
- /** Filter by tenant ID (superadmin only — alternative to X-Tenant-ID header) */
304
+ /** Filter by tenant ID (superadmin only — alternative to X-Tenant-ID header). */
177
305
  tenantId?: string;
178
306
  /**
179
307
  * Filter by forwarding status.
@@ -182,54 +310,178 @@ export interface CallListParams {
182
310
  * - omit: return all calls regardless of forwarding
183
311
  */
184
312
  forwarded?: 'true' | 'false';
185
- /** Search by the external number the call was forwarded to (partial match, case-insensitive) */
313
+ /** Search by the external number the call was forwarded to (partial match, case-insensitive). */
186
314
  forwardedTo?: string;
187
315
  }
316
+ /**
317
+ * Parameters for originating (placing) a new outbound call from a webphone/extension.
318
+ *
319
+ * The server creates a new call leg from the specified extension to the PSTN number
320
+ * and bridges it to the extension's WebRTC session.
321
+ *
322
+ * @example
323
+ * ```ts
324
+ * const { callUuid } = await voip.originateCall({
325
+ * fromExtension: '1001',
326
+ * toNumber: '+17865551234',
327
+ * });
328
+ * ```
329
+ */
188
330
  export interface OriginateParams {
331
+ /** Extension number to originate the call from. Must be an active extension in your tenant. Example: `"1001"`. */
189
332
  fromExtension: string;
333
+ /** Destination PSTN number in E.164 format. Example: `"+17865551234"`. */
190
334
  toNumber: string;
191
335
  }
336
+ /**
337
+ * Response from `originateCall()`.
338
+ *
339
+ * Contains the FreeSWITCH UUID of the outbound call leg for monitoring.
340
+ */
192
341
  export interface OriginateResponse {
342
+ /** Human-readable status message. Example: `"Call originated successfully"`. */
193
343
  message: string;
344
+ /** FreeSWITCH call UUID of the originated outbound leg. Use this to track the call. */
194
345
  callUuid: string;
195
346
  }
347
+ /**
348
+ * Parameters for transferring an active call to another destination.
349
+ *
350
+ * Supports blind transfer (immediate, no consultation) and attended transfer
351
+ * (speak to the target first, then merge).
352
+ *
353
+ * @example
354
+ * ```ts
355
+ * // Blind transfer — caller goes directly to target
356
+ * await voip.transferCall(callId, {
357
+ * targetExtension: '1002',
358
+ * type: 'blind',
359
+ * });
360
+ *
361
+ * // Attended transfer — you speak first, then complete the transfer
362
+ * await voip.transferCall(callId, {
363
+ * targetExtension: '1002',
364
+ * type: 'attended',
365
+ * });
366
+ * ```
367
+ */
196
368
  export interface TransferParams {
369
+ /** Target extension number to transfer the call to. Example: `"1002"`. */
197
370
  targetExtension: string;
371
+ /** Transfer type. `'blind'` = immediate (SIP REFER). `'attended'` = consult then complete (conference bridge). Default: `'blind'`. */
198
372
  type?: 'blind' | 'attended';
199
373
  }
374
+ /**
375
+ * Response from call eavesdropping (listen in on an active call).
376
+ *
377
+ * Returned by `eavesdropCall()`. Supports whisper (coach can talk to the agent
378
+ * without the caller hearing), spy (listen-only), and full (3-way join).
379
+ */
200
380
  export interface EavesdropResponse {
381
+ /** Human-readable message. Example: `"Whisper session started"`. */
201
382
  message: string;
383
+ /** FreeSWITCH UUID of the eavesdrop channel. */
202
384
  spyUuid: string;
385
+ /** FreeSWITCH UUID of the target call being monitored. */
203
386
  targetCallUuid: string;
387
+ /** Eavesdrop mode: `'whisper'`, `'spy'`, or `'full'`. */
204
388
  mode: string;
205
389
  }
390
+ /**
391
+ * A currently active (in-progress) call on the FreeSWITCH server.
392
+ *
393
+ * Returned by `listActiveCalls()`. Each entry represents one call leg (channel).
394
+ * For a two-party call, you'll see two entries — one for each leg.
395
+ *
396
+ * **Key field:** `uuid` — this is the FreeSWITCH channel UUID required for
397
+ * three-way calling operations (`addCallParticipant`, `mergeCalls`).
398
+ * It is NOT the same as `call_uuid` (which is the logical call identifier).
399
+ *
400
+ * @example
401
+ * ```ts
402
+ * // List all active calls and show the caller/destination
403
+ * const { calls } = await voip.listActiveCalls();
404
+ * calls.forEach(c => {
405
+ * console.log(`${c.caller_id_number} → ${c.destination} (${c.status})`);
406
+ * });
407
+ * ```
408
+ */
206
409
  export interface ActiveCall {
207
- /** FreeSWITCH channel UUID — required for three-way operations */
410
+ /** FreeSWITCH channel UUID — required for three-way operations. This is the server-side channel identifier. Example: `"a1b2c3d4-e5f6-7890-abcd-ef1234567890"`. */
208
411
  uuid: string;
412
+ /** Logical call UUID (same across both legs of a bridged call). Use for CDR matching and WebSocket event correlation. Example: `"c0ffee00-dead-beef-0000-000000000001"`. */
209
413
  call_uuid: string;
414
+ /** Caller display name from SIP header. Example: `"John Smith"`. */
210
415
  caller_id_name: string;
416
+ /** Caller phone number. Example: `"+17865551234"` or `"1001"` for internal calls. */
211
417
  caller_id_number: string;
418
+ /** Destination of the call. For outbound calls this is the PSTN number being dialed. For inbound this is the DID or extension. Example: `"+17869876543"`. */
212
419
  destination: string;
420
+ /** Call direction: `'inbound'`, `'outbound'`, or `'internal'`. */
213
421
  direction: string;
422
+ /** Channel state: `'CS_EXECUTE'`, `'CS_CONSUME_MEDIA'`, `'CS_HIBERNATE'`, etc. Use `answered` boolean for high-level state. */
214
423
  status: string;
424
+ /** ISO 8601 timestamp when the call channel was created. Example: `"2025-06-04T14:30:00Z"`. */
215
425
  started_at: string;
426
+ /** Whether the call has been answered (both parties connected). `false` during ringing/early-media. */
216
427
  answered: boolean;
428
+ /** Whether this channel currently has music-on-hold active. */
217
429
  on_hold: boolean;
218
430
  }
431
+ /**
432
+ * Quick call statistics for the current tenant (today and this month).
433
+ *
434
+ * Returned by `getCallStats()`. Use for dashboard summary badges.
435
+ *
436
+ * @example
437
+ * ```ts
438
+ * const { stats } = await voip.getCallStats();
439
+ * console.log(`Today: ${stats.total} calls (${stats.inbound} in, ${stats.outbound} out)`);
440
+ * ```
441
+ */
219
442
  export interface CallStats {
220
443
  stats: {
444
+ /** Total calls in the current period. */
221
445
  total: number;
446
+ /** Inbound calls in the current period. */
222
447
  inbound: number;
448
+ /** Outbound calls in the current period. */
223
449
  outbound: number;
450
+ /** Internal (extension-to-extension) calls in the current period. */
224
451
  internal: number;
452
+ /** Period description: `'today'` or `'month'`. */
225
453
  period: string;
226
454
  };
227
455
  }
456
+ /**
457
+ * A SIP extension (phone user) within a tenant.
458
+ *
459
+ * Extensions are the core entity — every person who makes/receives calls has one.
460
+ * Each extension has a SIP password for registration, voicemail settings,
461
+ * call forwarding rules, recording preferences, and real-time presence status.
462
+ *
463
+ * Returned by `listExtensions()`, `getExtension()`, `createExtension()`, and `updateExtension()`.
464
+ *
465
+ * @example
466
+ * ```ts
467
+ * // List all extensions and show their presence
468
+ * const { extensions } = await voip.listExtensions();
469
+ * extensions.forEach(ext => {
470
+ * const presenceIcon = ext.presence === 'on_call' ? '🟢' : ext.presence === 'offline' ? '⚫' : '⭕';
471
+ * console.log(`${presenceIcon} ${ext.extension} — ${ext.display_name}`);
472
+ * });
473
+ * ```
474
+ */
228
475
  export interface Extension {
476
+ /** Database UUID of the extension record. */
229
477
  id: string;
478
+ /** Tenant UUID this extension belongs to. Present for tenant-scoped queries; may be absent in superadmin global lists. */
230
479
  tenant_id?: string;
480
+ /** Extension number (3-6 digits). Used for dialing internally and as the SIP username. Example: `"1001"`. */
231
481
  extension: string;
482
+ /** Human-readable display name shown to other callers and in the dashboard. `null` if not set. Example: `"John Smith"`. */
232
483
  display_name: string | null;
484
+ /** Whether voicemail is enabled for this extension. When enabled, unanswered calls go to voicemail after the ring timeout. Example: `true`. */
233
485
  voicemail_enabled: boolean;
234
486
  /**
235
487
  * Whether call recording is enabled for this extension.
@@ -243,31 +495,68 @@ export interface Extension {
243
495
  * The tenant must also have `noise_cancellation_enabled = true` (the default) for NC to apply.
244
496
  */
245
497
  noise_cancellation_enabled?: boolean;
498
+ /** 4-6 digit PIN required to access voicemail via *97. `null` if no PIN is set (voicemail has no password protection). */
246
499
  voicemail_pin?: string | null;
500
+ /** Type of voicemail greeting: `'default'`, `'name'`, `'custom_audio'`, `'custom_tts'`. `null` if using default system greeting. */
247
501
  voicemail_greeting_type?: VoicemailGreetingType | null;
502
+ /** Text spoken for TTS greeting. `null` if not using TTS. Example: `"You've reached John. Please leave a message."`. */
248
503
  voicemail_greeting_text?: string | null;
504
+ /** Server path to uploaded custom audio greeting file. `null` if no custom audio. */
249
505
  voicemail_greeting_audio_path?: string | null;
506
+ /** Whether Do Not Disturb is enabled. When true, calls go directly to voicemail without ringing. */
250
507
  do_not_disturb: boolean;
508
+ /** Outbound caller ID (DID number) shown to recipients when this extension makes outbound calls. Falls back to tenant's first active DID if `null`. Example: `"+17868392727"`. */
251
509
  outbound_caller_id?: string | null;
510
+ /** Extension status: `'active'` (can register and make/receive calls), `'disabled'` (cannot register or call). */
252
511
  status: string;
253
- /** Real-time presence status: 'available', 'on_call', 'offline', 'do_not_disturb' */
512
+ /** Real-time presence status from Redis: `'available'`, `'on_call'`, `'offline'`, `'do_not_disturb'`. Use for presence indicators in the UI. Not persisted — comes from live registration/call state. */
254
513
  presence?: string;
514
+ /** ISO 8601 timestamp when this extension was created. Example: `"2025-01-15T10:30:00.000Z"`. */
255
515
  created_at: string;
516
+ /** Whether unconditional call forwarding is enabled. */
256
517
  call_forward_enabled?: boolean;
518
+ /** Number to forward calls to when `call_forward_enabled` is true. E.164 for external, extension number for internal. Example: `"+13051234567"`. */
257
519
  call_forward_number?: string | null;
520
+ /** Forward type: `'always'`, `'busy'`, or `'no-answer'`. `null` when forwarding is disabled. */
258
521
  call_forward_type?: string | null;
522
+ /** External CRM user ID for integration mapping. `null` if not linked to a CRM record. */
259
523
  crm_user_id?: string | null;
524
+ /** Arbitrary JSON metadata from CRM integration. `null` if no metadata set. */
260
525
  crm_metadata?: Record<string, unknown> | null;
261
- /** Present when queried as global superadmin */
526
+ /** Present when queried as global superadmin — contains tenant details. */
262
527
  tenants?: TenantInfo;
263
528
  }
529
+ /**
530
+ * Parameters for creating a new SIP extension.
531
+ *
532
+ * At minimum, provide `extension`, `password`, and `displayName`.
533
+ * All other fields are optional with sensible defaults.
534
+ *
535
+ * @example
536
+ * ```ts
537
+ * // Create a basic extension with voicemail PIN
538
+ * const { extension: ext } = await voip.createExtension({
539
+ * extension: '2001',
540
+ * password: 'secure123',
541
+ * displayName: 'Alice Jones',
542
+ * voicemailEnabled: true,
543
+ * voicemailPin: '1234',
544
+ * outboundCallerId: '+17868392727',
545
+ * }, { tenantId: 'tenant-uuid' });
546
+ * ```
547
+ */
264
548
  export interface CreateExtensionParams {
549
+ /** Extension number (3-6 digits). Must be unique within the tenant. Example: `"2001"`. */
265
550
  extension: string;
551
+ /** SIP password for registration. Min 6 characters. Used by desk phones and WebRTC softphones to authenticate. Example: `"secure123"`. */
266
552
  password: string;
553
+ /** Human-readable display name. Shown to other callers via caller ID name. Example: `"Alice Jones"`. */
267
554
  displayName: string;
555
+ /** Enable voicemail for this extension. Default: `true`. */
268
556
  voicemailEnabled?: boolean;
269
- /** 4-6 digit PIN required to check voicemail via *97. If not set, voicemail has no PIN protection. */
557
+ /** 4-6 digit PIN required to check voicemail via *97. If not set, voicemail has no PIN protection. Example: `"1234"`. */
270
558
  voicemailPin?: string;
559
+ /** Initial Do Not Disturb state. Default: `false`. */
271
560
  doNotDisturb?: boolean;
272
561
  /**
273
562
  * Whether to record all calls for this extension.
@@ -292,13 +581,38 @@ export interface CreateExtensionParams {
292
581
  */
293
582
  outboundCallerId?: string | null;
294
583
  }
584
+ /**
585
+ * Parameters for updating an existing SIP extension.
586
+ *
587
+ * All fields are optional — only include fields you want to change.
588
+ * Send `null` for string fields (like `voicemailPin`, `outboundCallerId`, `crmUserId`) to clear them.
589
+ *
590
+ * @example
591
+ * ```ts
592
+ * // Rename extension and enable DND
593
+ * await voip.updateExtension(extId, {
594
+ * displayName: 'Alice J.',
595
+ * doNotDisturb: true,
596
+ * });
597
+ *
598
+ * // Clear the outbound caller ID (revert to tenant default)
599
+ * await voip.updateExtension(extId, {
600
+ * outboundCallerId: null,
601
+ * });
602
+ * ```
603
+ */
295
604
  export interface UpdateExtensionParams {
605
+ /** New display name. Example: `"Alice Jones-Smith"`. */
296
606
  displayName?: string;
607
+ /** New SIP password. Min 6 characters. */
297
608
  password?: string;
609
+ /** Enable or disable voicemail. */
298
610
  voicemailEnabled?: boolean;
299
611
  /** 4-6 digit PIN for voicemail access. Set to null to remove PIN protection. */
300
612
  voicemailPin?: string | null;
613
+ /** Enable or disable Do Not Disturb. When true, calls go straight to voicemail. */
301
614
  doNotDisturb?: boolean;
615
+ /** Set extension status: `'active'` (can register/call) or `'disabled'` (blocked). */
302
616
  status?: 'active' | 'disabled';
303
617
  /**
304
618
  * Enable or disable call recording for this extension.
@@ -319,7 +633,9 @@ export interface UpdateExtensionParams {
319
633
  * Set to `null` to clear (calls will fall back to the tenant's first active DID).
320
634
  */
321
635
  outboundCallerId?: string | null;
636
+ /** CRM user ID for integration mapping. Set to `null` to unlink. */
322
637
  crmUserId?: string | null;
638
+ /** Arbitrary JSON metadata from CRM. Set to `null` to clear. */
323
639
  crmMetadata?: Record<string, unknown> | null;
324
640
  }
325
641
  export interface Tenant {
@@ -743,12 +1059,21 @@ export interface RecordingUrlResponse {
743
1059
  /** Always `null` — CDN URLs and local URLs don't expire. */
744
1060
  expiresIn: number | null;
745
1061
  }
1062
+ /**
1063
+ * Filtering/pagination params for `listRecordings()`.
1064
+ *
1065
+ * All fields optional. Omit a field to skip that filter.
1066
+ */
746
1067
  export interface RecordingListParams {
1068
+ /** Page number (1-indexed). Default: `1`. */
747
1069
  page?: number;
1070
+ /** Items per page. Default: `50`. */
748
1071
  limit?: number;
1072
+ /** ISO date string — recordings after this date. Example: `"2025-06-01T00:00:00.000Z"`. */
749
1073
  dateFrom?: string;
1074
+ /** ISO date string — recordings before this date. Example: `"2025-06-04T23:59:59.999Z"`. */
750
1075
  dateTo?: string;
751
- /** Filter by direction */
1076
+ /** Filter by direction. `'inbound'` for incoming call recordings, `'outbound'` for outgoing. */
752
1077
  direction?: 'inbound' | 'outbound';
753
1078
  }
754
1079
  export interface RecordingListResponse {
@@ -756,6 +1081,25 @@ export interface RecordingListResponse {
756
1081
  pagination: PaginationInfo;
757
1082
  }
758
1083
  export type PresenceStatus = 'available' | 'registered' | 'on_call' | 'busy' | 'ringing' | 'dnd' | 'idle' | 'offline';
1084
+ /**
1085
+ * Map of extension numbers to their current presence status.
1086
+ *
1087
+ * Keys are extension numbers (e.g. `"1001"`), values are presence status strings.
1088
+ * Use this for a quick presence overview — iterate keys and show status badges.
1089
+ *
1090
+ * For detailed presence (with call UUID, caller info, direction, timestamps),
1091
+ * use `listPresenceSubscriptions()` which returns `PresenceDetailMap`.
1092
+ *
1093
+ * @example
1094
+ * ```ts
1095
+ * const presence = await voip.getPresence();
1096
+ * // presence = { "1001": "on_call", "1002": "available", "1003": "offline" }
1097
+ * Object.entries(presence).forEach(([ext, status]) => {
1098
+ * const color = status === 'on_call' ? 'green' : status === 'offline' ? 'gray' : 'blue';
1099
+ * renderBadge(ext, status, color);
1100
+ * });
1101
+ * ```
1102
+ */
759
1103
  export interface PresenceMap {
760
1104
  [extension: string]: PresenceStatus | string;
761
1105
  }
@@ -887,16 +1231,75 @@ export interface WebRTCConfig {
887
1231
  */
888
1232
  jwtToken?: string;
889
1233
  }
1234
+ /**
1235
+ * Information about an active WebRTC call managed by the SIP.js softphone.
1236
+ *
1237
+ * ## CRITICAL: `id` vs `fsChannelUuid` — these are NOT the same thing
1238
+ *
1239
+ * | Field | What it is | When populated | Used for |
1240
+ * |-------|-----------|---------------|----------|
1241
+ * | `id` | sip.js session ID (local, client-generated) | Immediately (ringing) | Answer, reject, hold, mute, DTMF, hangup |
1242
+ * | `fsChannelUuid` | FreeSWITCH channel UUID (server-side) | AFTER connect (`state: 'established'`) | Three-way operations (`addCallParticipant`, `mergeCalls`) |
1243
+ *
1244
+ * **Never pass `id` to three-way methods.** Always use `fsChannelUuid` for
1245
+ * server-side operations. `id` is a sip.js internal identifier and has no meaning
1246
+ * on the FreeSWITCH server.
1247
+ *
1248
+ * ## Lifecycle
1249
+ *
1250
+ * ```
1251
+ * idle → connecting → ringing → established → terminating → terminated
1252
+ * ↕
1253
+ * held
1254
+ * ```
1255
+ *
1256
+ * - `idle`: No active call. Phone ready.
1257
+ * - `connecting`: Outbound call — sending INVITE, waiting for provisional response.
1258
+ * - `ringing`: Outbound — receiving 180 Ringing. Inbound — incoming call, waiting for answer.
1259
+ * - `established`: Call is connected, audio flows. `fsChannelUuid` becomes non-null here.
1260
+ * - `held`: Call is on hold (re-INVITE with sendonly). Music-on-hold plays to remote party.
1261
+ * - `terminating`: BYE sent or received, waiting for final ACK.
1262
+ * - `terminated`: Call ended. Resources released.
1263
+ *
1264
+ * ## UI guidelines
1265
+ *
1266
+ * - Show DTMF dialpad when `state === 'established'` and NOT `held`.
1267
+ * - Grey out hold button during `connecting` and `ringing` — hold is only available when established.
1268
+ * - Show "Calling..." during `connecting`, "Ringing..." during `ringing`, timer during `established`.
1269
+ * - If `isPaging === true`, auto-answer and route audio to speaker (no earpiece).
1270
+ * - Use `pagingGroup` and `pagingInitiator` to display "Paging: Sales Floor by 1001" in the UI.
1271
+ * - Use `callType` to show "WhatsApp Call" badge in the call screen.
1272
+ */
890
1273
  export interface WebRTCCallInfo {
1274
+ /**
1275
+ * sip.js session ID — a locally generated string (e.g. `"abc123"`).
1276
+ *
1277
+ * **This is NOT the FreeSWITCH UUID.** Use this for client-side operations only:
1278
+ * `answer()`, `reject()`, `hold()`, `mute()`, `sendDtmf()`, `hangup()`.
1279
+ *
1280
+ * Available immediately when the call is created (during `ringing` state).
1281
+ *
1282
+ * **DO NOT** pass this to `addCallParticipant()`, `mergeCalls()`, or any other
1283
+ * server-side method — those require `fsChannelUuid`.
1284
+ */
891
1285
  id: string;
1286
+ /** Call direction relative to this phone: `'inbound'` (someone called us) or `'outbound'` (we called someone). */
892
1287
  direction: 'inbound' | 'outbound';
1288
+ /** Remote party's phone number. For inbound calls this is the caller's number. For outbound calls this is the dialed number. Example: `"+17865551234"`. Initially `"unknown"` during very early ringing. */
893
1289
  remoteIdentity: string;
1290
+ /** Remote party's display name from SIP header. Example: `"John Doe"`. May be empty string if not provided. */
894
1291
  remoteDisplayName: string;
1292
+ /** Current state in the call lifecycle. See the type-level docs for the full state machine. */
895
1293
  state: WebRTCCallState;
1294
+ /** `Date` object when the call started (outbound INVITE sent or inbound INVITE received). `null` when `state === 'idle'`. */
896
1295
  startTime: Date | null;
1296
+ /** `Date` object when the call was answered (200 OK received/sent). `null` until `state === 'established'`. */
897
1297
  answerTime: Date | null;
1298
+ /** Whether the local user has placed this call on hold. `true` only during `held` state. */
898
1299
  held: boolean;
1300
+ /** Whether the local microphone is muted. Toggle via `phone.mute()`. The remote party hears silence but the call stays active. */
899
1301
  muted: boolean;
1302
+ /** String of DTMF digits sent during this call. Example: `""` (none sent), `"123"` (digits 1, 2, 3 sent). Accumulates over the call life. */
900
1303
  dtmfSent: string;
901
1304
  /**
902
1305
  * Channel type of the inbound call.
@@ -918,6 +1321,8 @@ export interface WebRTCCallInfo {
918
1321
  /**
919
1322
  * Whether this is a paging/intercom broadcast call.
920
1323
  * When `true`, the phone should auto-answer and play through the speaker (bocina).
1324
+ * The SDK handles auto-answer automatically via the `autoAnswer` config and the
1325
+ * `pagingCall` event on `WebRTCEventMap`.
921
1326
  */
922
1327
  isPaging?: boolean;
923
1328
  /**
@@ -940,6 +1345,10 @@ export interface WebRTCCallInfo {
940
1345
  *
941
1346
  * **Populated in `state: 'established'`** — `null` during ringing/connecting.
942
1347
  *
1348
+ * **Critical:** Do NOT confuse this with `id` (the sip.js session ID).
1349
+ * `fsChannelUuid` is the FreeSWITCH channel UUID needed for server-side operations.
1350
+ * `id` is the local sip.js session ID for client-side operations.
1351
+ *
943
1352
  * @example "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
944
1353
  */
945
1354
  fsChannelUuid: string | null;
@@ -968,40 +1377,104 @@ export interface WebRTCEventMap {
968
1377
  }) => void;
969
1378
  error: (error: Error) => void;
970
1379
  }
1380
+ /**
1381
+ * A participant in a conference room.
1382
+ *
1383
+ * Each member has a FreeSWITCH channel UUID (`uuid`) and a conference-specific
1384
+ * member ID (`id`). Use `id` for conference operations like mute/kick/deaf.
1385
+ */
971
1386
  export interface ConferenceMember {
1387
+ /** Conference member ID (integer). Used for mute/kick/deaf operations within the conference. Example: `"1"`. */
972
1388
  id: string;
1389
+ /** FreeSWITCH channel UUID for this member's call leg. Example: `"a1b2c3d4-e5f6-7890-abcd-ef1234567890"`. */
973
1390
  uuid: string;
1391
+ /** Caller ID name for this participant. Example: `"John Smith"`. */
974
1392
  callerIdName: string;
1393
+ /** Caller ID number for this participant. Example: `"+17865551234"` or `"1001"`. */
975
1394
  callerIdNumber: string;
1395
+ /** Whether this member is muted (cannot speak into conference). */
976
1396
  muted: boolean;
1397
+ /** Whether this member is deafened (cannot hear conference). */
977
1398
  deaf: boolean;
1399
+ /** ISO 8601 timestamp when this member joined the conference. Example: `"2025-06-04T14:30:00Z"`. */
978
1400
  joinTime: string;
979
1401
  }
1402
+ /**
1403
+ * An active conference room on the FreeSWITCH server.
1404
+ *
1405
+ * Returned by `listConferences()`. Shows the conference name, number of members,
1406
+ * lock status, runtime, and full member list with mute/deaf state.
1407
+ *
1408
+ * @example
1409
+ * ```ts
1410
+ * const { conferences } = await voip.listConferences();
1411
+ * conferences.forEach(conf => {
1412
+ * console.log(`${conf.name}: ${conf.memberCount} members, ${conf.locked ? 'locked' : 'open'}`);
1413
+ * conf.members.forEach(m => {
1414
+ * console.log(` ${m.callerIdNumber} muted=${m.muted} deaf=${m.deaf}`);
1415
+ * });
1416
+ * });
1417
+ * ```
1418
+ */
980
1419
  export interface Conference {
1420
+ /** Conference room name (e.g. `"conf_<uuid>"` or a custom name). */
981
1421
  name: string;
1422
+ /** Number of active participants currently in the room. */
982
1423
  memberCount: number;
1424
+ /** Whether the conference is locked (no new members can join). */
983
1425
  locked: boolean;
1426
+ /** Human-readable runtime string (e.g. `"0:05:23"` for 5 minutes, 23 seconds). */
984
1427
  runTime: string;
1428
+ /** List of all active participants with their mute/deaf state. */
985
1429
  members: ConferenceMember[];
986
1430
  }
1431
+ /**
1432
+ * A member (extension) within a ring group.
1433
+ *
1434
+ * Each member has a priority (for sequential strategy) and a delay before ringing.
1435
+ */
987
1436
  export interface RingGroupMember {
1437
+ /** Database UUID of this member entry. */
988
1438
  id: string;
1439
+ /** Extension number (e.g. `"1001"`). */
989
1440
  extension: string;
1441
+ /** Ring priority for sequential strategy. Lower numbers ring first. `1`-based. */
990
1442
  priority: number;
1443
+ /** Seconds to wait before ringing this member (applies to sequential strategy). Default: `0`. */
991
1444
  delay_seconds: number;
992
1445
  }
1446
+ /**
1447
+ * A ring group — rings multiple extensions when a call arrives.
1448
+ *
1449
+ * Strategies:
1450
+ * - `simultaneous`: Ring all members at once. First to answer gets the call.
1451
+ * - `sequential`: Ring members one at a time in priority order. Move to next after `ring_timeout`.
1452
+ * - `random`: Ring a random member.
1453
+ *
1454
+ * If no one answers within `ring_timeout`, execute `no_answer_action` on `no_answer_target`.
1455
+ */
993
1456
  export interface RingGroup {
1457
+ /** Database UUID of the ring group. */
994
1458
  id: string;
1459
+ /** Tenant UUID. Present for tenant-scoped queries. */
995
1460
  tenant_id?: string;
1461
+ /** Human-readable ring group name. Example: `"Sales Team"`. */
996
1462
  name: string;
1463
+ /** Ring strategy: `'simultaneous'`, `'sequential'`, or `'random'`. */
997
1464
  strategy: string;
1465
+ /** Total ring time in seconds before executing `no_answer_action`. Example: `30`. */
998
1466
  ring_timeout: number;
1467
+ /** Action when no one answers: `'voicemail'`, `'ivr'`, `'extension'`, `'hangup'`, `'ai_agent'`. */
999
1468
  no_answer_action: string;
1469
+ /** Target for `no_answer_action` (extension number, IVR UUID, etc.). `null` when action is `'hangup'`. */
1000
1470
  no_answer_target: string | null;
1471
+ /** Status: `'active'` or `'disabled'`. */
1001
1472
  status: string;
1473
+ /** ISO 8601 timestamp of creation. */
1002
1474
  created_at: string;
1475
+ /** Ordered list of ring group members. */
1003
1476
  members: RingGroupMember[];
1004
- /** Present when queried as global superadmin */
1477
+ /** Present when queried as global superadmin. */
1005
1478
  tenant?: TenantInfo;
1006
1479
  }
1007
1480
  export interface CreateRingGroupParams {
@@ -1016,33 +1489,75 @@ export interface CreateRingGroupParams {
1016
1489
  delaySeconds?: number;
1017
1490
  }>;
1018
1491
  }
1492
+ /**
1493
+ * An agent (extension) assigned to a call queue.
1494
+ *
1495
+ * Agents receive calls distributed by the queue strategy.
1496
+ * Queue managers (ext 6000) can add/remove themselves via `*45`/`*46`.
1497
+ */
1019
1498
  export interface QueueAgent {
1499
+ /** Database UUID of this agent assignment. */
1020
1500
  id: string;
1501
+ /** Extension number assigned to the queue. Example: `"1001"`. */
1021
1502
  extension: string;
1503
+ /** Agent tier/priority. Lower numbers = higher priority (gets calls first). Default: `5`. */
1022
1504
  priority: number;
1505
+ /** Agent penalty (post-call wrap-up delay). Higher = longer delay before next call. Default: `0`. */
1023
1506
  penalty: number;
1507
+ /** Agent status: `'available'`, `'on_call'`, `'paused'`, `'logged_out'`. */
1024
1508
  status: string;
1025
1509
  }
1510
+ /**
1511
+ * A call queue — distributes incoming calls among agents based on a strategy.
1512
+ *
1513
+ * Callers hear music-on-hold while waiting for an available agent.
1514
+ * Queue managers can log in/log out, pause, and monitor via FreeSWITCH codes.
1515
+ *
1516
+ * Strategies:
1517
+ * - `round-robin`: Cycle through agents in fixed order.
1518
+ * - `longest-idle`: Agent idle the longest gets the next call.
1519
+ * - `ring-all`: Ring all available agents simultaneously.
1520
+ * - `least-calls`: Agent with fewest calls today gets the next.
1521
+ * - `random`: Pick a random available agent.
1522
+ */
1026
1523
  export interface CallQueue {
1524
+ /** Database UUID of the queue. */
1027
1525
  id: string;
1526
+ /** Tenant UUID. */
1028
1527
  tenant_id?: string;
1528
+ /** Queue name displayed in dashboards and reports. Example: `"Support Queue"`. */
1029
1529
  name: string;
1530
+ /** Distribution strategy: `'round-robin'`, `'longest-idle'`, `'ring-all'`, `'least-calls'`, `'random'`. */
1030
1531
  strategy: string;
1532
+ /** Music-on-hold sound file to play while caller waits. Example: `"default"` or custom audio file name. */
1031
1533
  moh_sound: string;
1534
+ /** Announcement audio played to callers on entry (position in queue, estimated wait). `null` if disabled. */
1032
1535
  announce_sound: string | null;
1536
+ /** How often (seconds) to replay the announcement to waiting callers. Example: `60`. */
1033
1537
  announce_frequency: number;
1538
+ /** Maximum wait time in seconds before caller times out. Example: `300` (5 min). */
1034
1539
  max_wait_time: number;
1540
+ /** Maximum number of simultaneous callers allowed in the queue. Example: `20`. */
1035
1541
  max_callers: number;
1542
+ /** Seconds each agent's phone rings before moving to next agent. Example: `30`. */
1036
1543
  ring_timeout: number;
1544
+ /** Seconds after a call ends before the agent gets the next call (post-call work). Example: `10`. */
1037
1545
  wrap_up_time: number;
1546
+ /** Action when no agents are logged in: `'voicemail'`, `'ivr'`, `'extension'`, `'hangup'`, `'ai_agent'`. */
1038
1547
  no_agent_action: string;
1548
+ /** Target for `no_agent_action`. `null` when action is `'hangup'`. */
1039
1549
  no_agent_target: string | null;
1550
+ /** Action when caller times out (exceeds `max_wait_time`): `'voicemail'`, `'ivr'`, `'extension'`, `'hangup'`, `'ai_agent'`. */
1040
1551
  timeout_action: string;
1552
+ /** Target for `timeout_action`. `null` when action is `'hangup'`. */
1041
1553
  timeout_target: string | null;
1554
+ /** Queue status: `'active'` or `'disabled'`. */
1042
1555
  status: string;
1556
+ /** ISO 8601 timestamp of creation. */
1043
1557
  created_at: string;
1558
+ /** List of agents assigned to this queue. */
1044
1559
  agents: QueueAgent[];
1045
- /** Present when queried as global superadmin */
1560
+ /** Present when queried as global superadmin. */
1046
1561
  tenant?: TenantInfo;
1047
1562
  }
1048
1563
  export interface CreateQueueParams {
@@ -1065,18 +1580,43 @@ export interface CreateQueueParams {
1065
1580
  penalty?: number;
1066
1581
  }>;
1067
1582
  }
1583
+ /**
1584
+ * A webhook subscription that sends call events to an external URL.
1585
+ *
1586
+ * Webhooks fire on call lifecycle events (`call.started`, `call.ended`, etc.),
1587
+ * voicemail events, and extension registration changes.
1588
+ * Each delivery is retried up to `maxRetries` times with exponential backoff.
1589
+ *
1590
+ * @example
1591
+ * ```ts
1592
+ * const { webhooks } = await voip.listWebhooks();
1593
+ * webhooks.forEach(w => {
1594
+ * console.log(`${w.name} → ${w.url} [${w.events.join(',')}] ${w.active ? 'ACTIVE' : 'PAUSED'}`);
1595
+ * });
1596
+ * ```
1597
+ */
1068
1598
  export interface Webhook {
1599
+ /** Database UUID of the webhook subscription. */
1069
1600
  id: string;
1601
+ /** Human-readable name for this webhook. Example: `"CRM Call Logger"`. */
1070
1602
  name: string;
1603
+ /** Destination URL where HTTP POST requests are sent. Must be HTTPS. Example: `"https://my-crm.example.com/api/webhooks/voip"`. */
1071
1604
  url: string;
1605
+ /** Array of event types this webhook listens to. Example: `["call.started", "call.ended", "call.answered"]`. */
1072
1606
  events: string[];
1607
+ /** Whether this webhook is actively sending events. `false` means paused. */
1073
1608
  active: boolean;
1609
+ /** Whether a signing secret is configured. Always `false` in GET responses — the secret is never returned. */
1074
1610
  hasSecret: boolean;
1611
+ /** Custom HTTP headers included in each delivery. `null` if none. Example: `{"X-Custom-Auth": "token123"}`. */
1075
1612
  headers: Record<string, string> | null;
1613
+ /** Maximum retry attempts for failed deliveries. Default: `3`. After exhausting retries, the delivery is marked as failed. */
1076
1614
  maxRetries?: number;
1615
+ /** Base delay in seconds between retries (exponential backoff). Default: `10`. Delays: 10s, 20s, 40s, ... */
1077
1616
  retryDelaySeconds?: number;
1617
+ /** ISO 8601 timestamp of webhook creation. */
1078
1618
  createdAt: string;
1079
- /** Present when queried as global superadmin */
1619
+ /** Present when queried as global superadmin. */
1080
1620
  tenant?: TenantInfo;
1081
1621
  }
1082
1622
  export interface WebhookDelivery {
@@ -1090,13 +1630,36 @@ export interface WebhookDelivery {
1090
1630
  error: string | null;
1091
1631
  deliveredAt: string;
1092
1632
  }
1633
+ /**
1634
+ * Parameters for creating a new webhook subscription.
1635
+ *
1636
+ * At minimum, provide `name`, `url`, and `events`. The server validates the URL
1637
+ * is HTTPS (non-negotiable for security) and tests connectivity before saving.
1638
+ *
1639
+ * @example
1640
+ * ```ts
1641
+ * await voip.createWebhook({
1642
+ * name: 'CRM Call Logger',
1643
+ * url: 'https://my-crm.example.com/api/webhooks/voip',
1644
+ * events: ['call.started', 'call.answered', 'call.ended', 'voicemail.new'],
1645
+ * secret: 'whsec_my-signing-secret',
1646
+ * });
1647
+ * ```
1648
+ */
1093
1649
  export interface CreateWebhookParams {
1650
+ /** Human-readable name for this webhook. Example: `"CRM Call Logger"`. */
1094
1651
  name: string;
1652
+ /** Destination HTTPS URL. Must be reachable from the server. Example: `"https://my-crm.example.com/webhook"`. */
1095
1653
  url: string;
1654
+ /** Array of event types to subscribe to. Full list: see `WebhookEventType`. Example: `["call.started", "call.ended"]`. */
1096
1655
  events: string[];
1656
+ /** Signing secret for HMAC payload verification. The server includes `X-Webhook-Signature` header. Optional but recommended. */
1097
1657
  secret?: string;
1658
+ /** Custom HTTP headers to include in each delivery. Example: `{"X-API-Key": "mykey"}`. */
1098
1659
  headers?: Record<string, string>;
1660
+ /** Maximum retry attempts for failed deliveries. Default: `3`. */
1099
1661
  maxRetries?: number;
1662
+ /** Base delay in seconds between retries (exponential: delay * 2^attempt). Default: `10`. */
1100
1663
  retryDelaySeconds?: number;
1101
1664
  }
1102
1665
  /** Supported webhook event names */
@@ -1237,23 +1800,55 @@ export interface VoicemailCallInfo {
1237
1800
  audio_url: string | null;
1238
1801
  started_at: string | null;
1239
1802
  }
1803
+ /**
1804
+ * A voicemail message left by a caller.
1805
+ *
1806
+ * Returned by `listVoicemails()`. Each message includes the caller's info,
1807
+ * duration, read/urgent flags, an audio URL, and optionally a linked call record.
1808
+ *
1809
+ * ## Playback
1810
+ *
1811
+ * Use `audio_url` with `voip.buildUrl()` to append the API key for browser playback:
1812
+ * ```html
1813
+ * <audio src={voip.buildUrl(message.audio_url)} controls />
1814
+ * ```
1815
+ *
1816
+ * @example
1817
+ * ```ts
1818
+ * const { messages, unread } = await voip.listVoicemails({ unreadOnly: true });
1819
+ * messages.forEach(msg => {
1820
+ * console.log(`From ${msg.caller_id}: ${msg.duration_seconds}s ${msg.is_urgent ? 'URGENT' : ''}`);
1821
+ * });
1822
+ * ```
1823
+ */
1240
1824
  export interface VoicemailMessage {
1825
+ /** Database UUID of the voicemail message. */
1241
1826
  id: string;
1827
+ /** Tenant UUID this message belongs to. */
1242
1828
  tenant_id: string;
1829
+ /** Extension number that received the voicemail. Example: `"1001"`. */
1243
1830
  extension: string;
1831
+ /** Caller's phone number. Example: `"+17865551234"`. */
1244
1832
  caller_id: string;
1833
+ /** Caller's display name. `null` if not provided by carrier. Example: `"John Doe"`. */
1245
1834
  caller_name: string | null;
1835
+ /** Duration of the voicemail recording in seconds. Example: `42`. */
1246
1836
  duration_seconds: number;
1837
+ /** Whether the voicemail has been listened to. */
1247
1838
  is_read: boolean;
1839
+ /** Whether this voicemail was marked as urgent by the caller (pressed * during recording). */
1248
1840
  is_urgent: boolean;
1841
+ /** ISO 8601 timestamp when the voicemail was left. Example: `"2025-06-04T15:30:00.000Z"`. */
1249
1842
  created_at: string;
1843
+ /** ISO 8601 timestamp when the voicemail was read. `null` if unread. */
1250
1844
  read_at: string | null;
1251
- /** Direct URL to stream this voicemail's audio. Append `?apiKey=...` for browser playback. */
1845
+ /** Direct URL to stream this voicemail's audio. Append `?apiKey=...` for browser playback. Example: `"/api/voicemail/abc123/audio"`. */
1252
1846
  audio_url: string;
1253
- /** Linked call record with status, recording, etc. (null if no matching call found) */
1847
+ /** Linked call record with status, recording, etc. (null if no matching call found). Available since SDK 1.55.4. */
1254
1848
  call: VoicemailCallInfo | null;
1255
- /** Present when queried as global superadmin */
1849
+ /** Present when queried as global superadmin. Tenant company name. */
1256
1850
  company_name?: string;
1851
+ /** Present when queried as global superadmin. Tenant subdomain. */
1257
1852
  subdomain?: string;
1258
1853
  }
1259
1854
  export interface VoicemailListParams {
@@ -1333,11 +1928,28 @@ export interface PresenceDetail {
1333
1928
  extension?: string;
1334
1929
  }
1335
1930
  export type PresenceDetailMap = Record<string, PresenceDetail>;
1931
+ /**
1932
+ * Dashboard summary counters for the current tenant.
1933
+ *
1934
+ * Returned by `getDashboardStats()`. Use for summary cards/badges at the top
1935
+ * of a CRM dashboard showing: total extensions, active DIDs, calls today, and calls this month.
1936
+ *
1937
+ * @example
1938
+ * ```ts
1939
+ * const { dashboard } = await voip.getDashboardStats();
1940
+ * console.log(`Extensions: ${dashboard.extensions}, DIDs: ${dashboard.dids}`);
1941
+ * console.log(`Calls today: ${dashboard.callsToday}, This month: ${dashboard.callsThisMonth}`);
1942
+ * ```
1943
+ */
1336
1944
  export interface DashboardStats {
1337
1945
  dashboard: {
1946
+ /** Total number of extensions configured in this tenant. */
1338
1947
  extensions: number;
1948
+ /** Total number of active DID phone numbers. */
1339
1949
  dids: number;
1950
+ /** Number of calls made/received today (midnight to now). */
1340
1951
  callsToday: number;
1952
+ /** Number of calls made/received this calendar month. */
1341
1953
  callsThisMonth: number;
1342
1954
  };
1343
1955
  }
@@ -1359,19 +1971,46 @@ export interface TopExtension {
1359
1971
  export interface TopExtensionsResponse {
1360
1972
  topExtensions: TopExtension[];
1361
1973
  }
1974
+ /**
1975
+ * A blocked phone number in the tenant's blocklist.
1976
+ *
1977
+ * Calls to/from blocked numbers are automatically rejected by FreeSWITCH.
1978
+ * Works for both inbound and outbound directions.
1979
+ */
1362
1980
  export interface BlockedNumber {
1981
+ /** Database UUID of the blocklist entry. */
1363
1982
  id: string;
1983
+ /** Tenant UUID. */
1364
1984
  tenant_id: string;
1985
+ /** Blocked phone number in E.164 format. Example: `"+17865559999"`. */
1365
1986
  number: string;
1987
+ /** Reason for blocking. `null` if no reason was provided. Example: `"Spam caller"`. */
1366
1988
  reason: string | null;
1989
+ /** Direction this block applies to: `'inbound'`, `'outbound'`, `'both'`. `null` = `'both'`. */
1367
1990
  direction: string | null;
1991
+ /** ISO 8601 timestamp when this number was blocked. `null` for legacy entries. */
1368
1992
  created_at: string | null;
1369
- /** Present when queried as global superadmin */
1993
+ /** Present when queried as global superadmin. */
1370
1994
  tenants?: TenantInfo;
1371
1995
  }
1996
+ /**
1997
+ * Parameters for adding a number to the blocklist.
1998
+ *
1999
+ * @example
2000
+ * ```ts
2001
+ * await voip.blockNumber({
2002
+ * number: '+17865559999',
2003
+ * reason: 'Repeated spam calls',
2004
+ * direction: 'inbound',
2005
+ * });
2006
+ * ```
2007
+ */
1372
2008
  export interface CreateBlockedNumberParams {
2009
+ /** E.164 phone number to block. Example: `"+17865559999"`. */
1373
2010
  number: string;
2011
+ /** Optional reason (shown in dashboard). Example: `"Spam caller"`. */
1374
2012
  reason?: string;
2013
+ /** Which direction to block: `'inbound'` (calls FROM this number), `'outbound'` (calls TO this number), `'both'`. Default: `'both'`. */
1375
2014
  direction?: 'inbound' | 'outbound' | 'both';
1376
2015
  }
1377
2016
  export interface BlocklistCheckResponse {
@@ -1388,27 +2027,81 @@ export interface Holiday {
1388
2027
  date: string;
1389
2028
  name?: string;
1390
2029
  }
2030
+ /**
2031
+ * A business hours schedule for a tenant.
2032
+ *
2033
+ * Defines which days/times the business is open. When a call arrives outside
2034
+ * business hours, the `after_hours_action` is executed (e.g. send to voicemail).
2035
+ *
2036
+ * Includes weekly `schedules` (day of week + start/end time) and `holidays`
2037
+ * (specific dates when the business is closed regardless of weekly schedule).
2038
+ *
2039
+ * @example
2040
+ * ```ts
2041
+ * const { schedules } = await voip.listSchedules();
2042
+ * schedules.forEach(s => {
2043
+ * const status = await voip.checkScheduleStatus(s.id);
2044
+ * console.log(`${s.name}: ${status.isOpen ? 'OPEN' : 'CLOSED'}`);
2045
+ * });
2046
+ * ```
2047
+ */
1391
2048
  export interface BusinessSchedule {
2049
+ /** Database UUID of the schedule. */
1392
2050
  id: string;
2051
+ /** Tenant UUID. */
1393
2052
  tenant_id: string;
2053
+ /** Human-readable schedule name. Example: `"Standard Business Hours"`. */
1394
2054
  name: string;
1395
- /** Present when queried as global superadmin */
2055
+ /** Present when queried as global superadmin. */
1396
2056
  tenants?: TenantInfo;
2057
+ /** IANA timezone for this schedule. `null` = tenant default. Example: `"America/New_York"`. */
1397
2058
  timezone: string | null;
2059
+ /** Weekly day schedule array. Each entry defines open hours for one day. `null` if not configured. */
1398
2060
  schedules: DaySchedule[] | null;
2061
+ /** Holiday list — specific dates the business is closed. `null` if no holidays configured. */
1399
2062
  holidays: Holiday[] | null;
2063
+ /** Action when a call arrives outside business hours: `'voicemail'`, `'ivr'`, `'extension'`, `'hangup'`, `'external'`, `'ai_agent'`. `null` if not configured. */
1400
2064
  after_hours_action: string | null;
2065
+ /** Target for `after_hours_action`. `null` when action is `'hangup'` or not configured. */
1401
2066
  after_hours_target: string | null;
2067
+ /** Schedule status: `'active'` or `'disabled'`. `null` for legacy entries. */
1402
2068
  status: string | null;
2069
+ /** ISO 8601 timestamp of creation. `null` for legacy entries. */
1403
2070
  created_at: string | null;
2071
+ /** ISO 8601 timestamp of last update. `null` for legacy entries. */
1404
2072
  updated_at: string | null;
1405
2073
  }
2074
+ /**
2075
+ * Parameters for creating a business hours schedule.
2076
+ *
2077
+ * @example
2078
+ * ```ts
2079
+ * await voip.createSchedule({
2080
+ * name: 'Standard Business Hours',
2081
+ * timezone: 'America/New_York',
2082
+ * schedules: [
2083
+ * { day: 'monday', enabled: true, startTime: '09:00', endTime: '17:00' },
2084
+ * { day: 'tuesday', enabled: true, startTime: '09:00', endTime: '17:00' },
2085
+ * { day: 'saturday', enabled: false },
2086
+ * { day: 'sunday', enabled: false },
2087
+ * ],
2088
+ * afterHoursAction: 'voicemail',
2089
+ * afterHoursTarget: '1001',
2090
+ * });
2091
+ * ```
2092
+ */
1406
2093
  export interface CreateScheduleParams {
2094
+ /** Human-readable name. Example: `"Standard Business Hours"`. */
1407
2095
  name: string;
2096
+ /** IANA timezone. Default: tenant's configured timezone or `"America/New_York"`. */
1408
2097
  timezone?: string;
2098
+ /** Weekly day schedule array. Each entry specifies open hours for a single day. Example: `[{ day: 'monday', enabled: true, startTime: '09:00', endTime: '17:00' }]`. */
1409
2099
  schedules?: DaySchedule[];
2100
+ /** Specific dates the business is closed. Example: `[{ date: '2025-12-25', name: 'Christmas' }]`. */
1410
2101
  holidays?: Holiday[];
2102
+ /** Action when a call arrives outside business hours. Defaults to no special handling. */
1411
2103
  afterHoursAction?: 'voicemail' | 'ivr' | 'extension' | 'hangup' | 'external' | 'ai_agent';
2104
+ /** Target for `afterHoursAction` (extension number, IVR UUID, phone number, etc.). */
1412
2105
  afterHoursTarget?: string;
1413
2106
  }
1414
2107
  export interface ScheduleStatusResponse {
@@ -1417,15 +2110,104 @@ export interface ScheduleStatusResponse {
1417
2110
  timezone: string;
1418
2111
  currentTime: string;
1419
2112
  }
2113
+ /**
2114
+ * Live gateway status reported by FreeSWITCH for a SIP trunk.
2115
+ *
2116
+ * Included in `SipTrunk` responses when the gateway is registered and available.
2117
+ * Shows the current call count, failures, and uptime.
2118
+ */
1420
2119
  export interface GatewayStatus {
2120
+ /** Gateway state: `'UP'` or `'DOWN'`. */
1421
2121
  state: string;
2122
+ /** Registration status: `'REGED'` (registered), `'UNREG'` (unregistered), `'TRYING'`. */
1422
2123
  status: string;
2124
+ /** Number of active inbound calls on this trunk. */
1423
2125
  callsIn: number;
2126
+ /** Number of active outbound calls on this trunk. */
1424
2127
  callsOut: number;
2128
+ /** Cumulative failed inbound calls. */
1425
2129
  failedIn?: number;
2130
+ /** Cumulative failed outbound calls. */
1426
2131
  failedOut?: number;
2132
+ /** Human-readable uptime string (e.g. `"3d 12h 45m"`). */
1427
2133
  uptime?: string;
1428
2134
  }
2135
+ /**
2136
+ * A SIP trunk gateway connecting the platform to an external telephony provider
2137
+ * (Twilio, Telnyx, Vonage, etc.).
2138
+ *
2139
+ * SIP trunks handle PSTN connectivity — outbound calls go through trunks to reach
2140
+ * phone numbers; inbound calls from phone numbers arrive via trunks.
2141
+ *
2142
+ * Global trunks (`tenant_id = null`) are shared across all tenants.
2143
+ * Tenant-specific trunks are only usable by that tenant.
2144
+ */
2145
+ export interface SipTrunk {
2146
+ /** Database UUID of the trunk. */
2147
+ id: string;
2148
+ /** NULL for global trunks (shared, not tied to any tenant). */
2149
+ tenant_id: string | null;
2150
+ /** Present when queried as global superadmin. */
2151
+ tenants?: TenantInfo;
2152
+ /** Human-readable trunk name. Example: `"Twilio Primary"`. */
2153
+ name: string;
2154
+ /** Provider name: `'twilio'`, `'telnyx'`, `'vonage'`, etc. `null` for custom/unspecified. */
2155
+ provider: string | null;
2156
+ /** Gateway IP or hostname. Example: `"sip.twilio.com"`. */
2157
+ gateway: string;
2158
+ /** SIP username for registration/auth. `null` for IP-based auth trunks. */
2159
+ username: string | null;
2160
+ /** SIP password (masked in API responses — always `"****"` except on create). `null` for IP-auth. */
2161
+ password: string | null;
2162
+ /** Authentication type: `'ip'`, `'registration'`, `'both'`. `null` for legacy entries. */
2163
+ auth_type: string | null;
2164
+ /** Whether outbound calling is enabled through this trunk. `null` = disabled. */
2165
+ outbound_enabled: boolean | null;
2166
+ /** Whether inbound calling is accepted from this trunk. `null` = disabled. */
2167
+ inbound_enabled: boolean | null;
2168
+ /** Priority for outbound routing. Lower = preferred. Example: `10`. */
2169
+ priority: number | null;
2170
+ /** Maximum simultaneous channels. `null` = unlimited. */
2171
+ max_channels: number | null;
2172
+ /** Trunk status: `'active'` or `'inactive'`. `null` = `'inactive'`. */
2173
+ status: string | null;
2174
+ /** SIP realm for authentication. `null` = auto. */
2175
+ realm: string | null;
2176
+ /** Outbound proxy address. `null` = direct to gateway. */
2177
+ proxy: string | null;
2178
+ /** Whether FreeSWITCH registers with the trunk provider. `null` = false. */
2179
+ register: boolean | null;
2180
+ /** From: username for SIP requests. `null` = use `username`. */
2181
+ from_user: string | null;
2182
+ /** From: domain for SIP requests. `null` = use gateway. */
2183
+ from_domain: string | null;
2184
+ /** SIP transport protocol: `'udp'`, `'tcp'`, `'tls'`. `null` = `'udp'`. */
2185
+ transport: string | null;
2186
+ /** Preferred codec list (comma-separated). `null` = platform default. Example: `"PCMU,PCMA"`. */
2187
+ codec_prefs: string | null;
2188
+ /** Whether to include caller ID in From: header. `null` = true. */
2189
+ caller_id_in_from: boolean | null;
2190
+ /** SIP OPTIONS ping interval in seconds. `null` = no ping. */
2191
+ ping: number | null;
2192
+ /** Seconds between registration retries. `null` = default. */
2193
+ retry_seconds: number | null;
2194
+ /** Registration expiry in seconds. `null` = default (3600). */
2195
+ expire_seconds: number | null;
2196
+ /** Separate proxy for REGISTER requests. `null` = use `proxy` or `gateway`. */
2197
+ register_proxy: string | null;
2198
+ /** Extra SIP contact header parameters. `null` = none. */
2199
+ contact_params: string | null;
2200
+ /** Whether this is a global trunk (usable by all tenants). `null` = false. */
2201
+ is_global: boolean | null;
2202
+ /** FreeSWITCH gateway profile name. `null` = auto-generated from name. */
2203
+ gateway_name: string | null;
2204
+ /** Live gateway status from FreeSWITCH (when available). Shows state, calls, failures, uptime. */
2205
+ gatewayStatus?: GatewayStatus | null;
2206
+ /** ISO 8601 timestamp of creation. `null` for legacy entries. */
2207
+ created_at: string | null;
2208
+ /** ISO 8601 timestamp of last update. `null` for legacy entries. */
2209
+ updated_at: string | null;
2210
+ }
1429
2211
  export interface SipTrunk {
1430
2212
  id: string;
1431
2213
  /** NULL for global trunks (shared, not tied to any tenant) */
@@ -1490,21 +2272,48 @@ export interface CreateTrunkParams {
1490
2272
  contactParams?: string;
1491
2273
  isGlobal?: boolean;
1492
2274
  }
2275
+ /**
2276
+ * Real-time and today's statistics for a single call queue.
2277
+ *
2278
+ * Returned by `getQueueStats()`. Shows agent availability, today's call metrics,
2279
+ * and service level percentage. Use for queue wallboards and agent dashboards.
2280
+ *
2281
+ * @example
2282
+ * ```ts
2283
+ * const stats = await voip.getQueueStats('queue-uuid');
2284
+ * console.log(`${stats.queueName}: ${stats.today.answered}/${stats.today.totalCalls} answered`);
2285
+ * console.log(`Agents: ${stats.agents.available} available, ${stats.agents.busy} busy`);
2286
+ * ```
2287
+ */
1493
2288
  export interface QueueStats {
2289
+ /** Queue name. Example: `"Support Queue"`. */
1494
2290
  queueName: string;
2291
+ /** Distribution strategy. Example: `"longest-idle"`. */
1495
2292
  strategy: string;
2293
+ /** Agent availability breakdown. */
1496
2294
  agents: {
2295
+ /** Total number of agents assigned to this queue. */
1497
2296
  total: number;
2297
+ /** Agents currently available to take calls. */
1498
2298
  available: number;
2299
+ /** Agents who are paused (taking a break). */
1499
2300
  paused: number;
2301
+ /** Agents currently on a call. */
1500
2302
  busy: number;
2303
+ /** Agents who are logged out. */
1501
2304
  loggedOut: number;
1502
2305
  };
2306
+ /** Today's call statistics (from midnight). */
1503
2307
  today: {
2308
+ /** Total calls offered to the queue today. */
1504
2309
  totalCalls: number;
2310
+ /** Calls successfully answered by an agent today. */
1505
2311
  answered: number;
2312
+ /** Calls abandoned by the caller before reaching an agent. */
1506
2313
  abandoned: number;
2314
+ /** Service level: percentage of calls answered within the SLA (default 20 seconds). Range 0-100. */
1507
2315
  serviceLevel: number;
2316
+ /** Average call duration in seconds for answered calls today. */
1508
2317
  avgDuration: number;
1509
2318
  };
1510
2319
  }
@@ -1514,38 +2323,118 @@ export interface ExportCallsParams {
1514
2323
  direction?: 'inbound' | 'outbound' | 'internal' | 'all';
1515
2324
  limit?: number;
1516
2325
  }
2326
+ /**
2327
+ * SIP registration credentials for WebRTC softphone authentication.
2328
+ *
2329
+ * Returned by `getSipCredentials()` when creating an extension or manually.
2330
+ * Pass these to the `WebRTCPhone` constructor for SIP registration.
2331
+ *
2332
+ * @example
2333
+ * ```ts
2334
+ * const creds = await voip.getSipCredentials('1001');
2335
+ * const phone = new WebRTCPhone({
2336
+ * extension: creds.extension,
2337
+ * password: creds.password,
2338
+ * displayName: creds.displayName,
2339
+ * sipDomain: creds.sipDomain,
2340
+ * wsUri: creds.wsUri,
2341
+ * });
2342
+ * ```
2343
+ */
1517
2344
  export interface SipCredentials {
2345
+ /** Extension number used as SIP username. Example: `"1001"`. */
1518
2346
  extension: string;
2347
+ /** Display name for caller ID. Example: `"John Smith"`. */
1519
2348
  displayName: string;
2349
+ /** SIP password for registration. */
1520
2350
  password: string;
2351
+ /** SIP domain the phone should register to. Example: `"demo.sip.cemscale.com"`. */
1521
2352
  sipDomain: string;
2353
+ /** WebSocket URI for SIP signaling. Example: `"wss://sip.cemscale.com/ws"`. */
1522
2354
  wsUri: string;
2355
+ /** SIP registrar address (same as sipDomain but explicit for sip.js config). Example: `"sip.cemscale.com"`. */
1523
2356
  registrar: string;
1524
2357
  }
2358
+ /**
2359
+ * An API key for authenticating API requests.
2360
+ *
2361
+ * API keys are the recommended way to authenticate SDK requests in production
2362
+ * (server-side integrations, CRMs, automation scripts). They never expire by
2363
+ * default and have role-based scopes.
2364
+ *
2365
+ * **CRITICAL:** The full key is only returned on `createApiKey()` and
2366
+ * `regenerateApiKey()` responses. After that, only `keyPreview` is shown.
2367
+ * Store the full key securely — it cannot be retrieved again.
2368
+ *
2369
+ * @example
2370
+ * ```ts
2371
+ * const { apiKey } = await voip.createApiKey({
2372
+ * name: 'CRM Integration',
2373
+ * role: 'admin',
2374
+ * });
2375
+ * console.log(apiKey.key); // "csk_live_abc123def456..." — STORE THIS NOW
2376
+ * console.log(apiKey.keyPreview); // "csk_live_••••••••def456"
2377
+ * ```
2378
+ */
1525
2379
  export interface ApiKey {
2380
+ /** Database UUID of the API key. */
1526
2381
  id: string;
2382
+ /** Human-readable name for this key. Example: `"CRM Integration"`. */
1527
2383
  name: string;
1528
- /** Full raw key — only present on create and regenerate responses */
2384
+ /** Full raw key — only present on create and regenerate responses. Format: `"csk_live_..."`. **Store securely.** Will be `undefined` in list/get responses. */
1529
2385
  key?: string;
1530
- /** Masked preview: csk_live_••••••••abcd1234 */
2386
+ /** Masked preview: csk_live_••••••••abcd1234. Safe to display in UI. Always present. */
1531
2387
  keyPreview: string;
2388
+ /** Role determining permissions: `'admin'`, `'readonly'`, `'user'`, `'superadmin'`. */
1532
2389
  role: string;
2390
+ /** API permission scopes. Example: `["read:calls", "write:extensions"]`. */
1533
2391
  scopes: string[];
2392
+ /** ISO 8601 timestamp of last usage. `null` if never used. */
1534
2393
  lastUsedAt: string | null;
2394
+ /** ISO 8601 timestamp when this key expires. `null` if never expires. */
1535
2395
  expiresAt: string | null;
2396
+ /** Key status: `'active'` or `'revoked'`. */
1536
2397
  status: string;
2398
+ /** Who created this key (email or user ID). `null` for legacy keys. */
1537
2399
  createdBy: string | null;
2400
+ /** ISO 8601 timestamp of creation. `null` for legacy keys. */
1538
2401
  createdAt: string | null;
2402
+ /** ISO 8601 timestamp when this key was revoked. `null` if active. */
1539
2403
  revokedAt?: string | null;
1540
2404
  }
2405
+ /**
2406
+ * Parameters for creating a new API key.
2407
+ *
2408
+ * At minimum, provide a `name`. The role defaults to `'admin'`.
2409
+ * Use `scopes` for fine-grained permission control.
2410
+ *
2411
+ * Superadmin-only fields (`global`, `tenantId`) allow creating keys
2412
+ * that span tenants or target specific tenants.
2413
+ *
2414
+ * @example
2415
+ * ```ts
2416
+ * // Admin key with full CRUD
2417
+ * const { apiKey } = await voip.createApiKey({ name: 'CRM Admin', role: 'admin' });
2418
+ *
2419
+ * // Read-only key for reporting
2420
+ * const { apiKey } = await voip.createApiKey({ name: 'Reports', role: 'readonly' });
2421
+ *
2422
+ * // Superadmin: create global key for all tenants
2423
+ * const { apiKey } = await voip.createApiKey({ name: 'Global Ops', role: 'superadmin', global: true });
2424
+ * ```
2425
+ */
1541
2426
  export interface CreateApiKeyParams {
2427
+ /** Human-readable name. Example: `"CRM Integration"`. */
1542
2428
  name: string;
2429
+ /** Role for permission level: `'admin'` (full CRUD), `'readonly'` (GET only), `'user'` (limited), `'superadmin'` (full PBX). Default: `'admin'`. */
1543
2430
  role?: 'admin' | 'readonly' | 'user' | 'superadmin';
2431
+ /** API permission scopes for fine-grained control. Example: `["read:calls", "write:extensions", "read:recordings"]`. */
1544
2432
  scopes?: string[];
2433
+ /** ISO 8601 expiration date. `null` (omit) = never expires. Example: `"2026-12-31T23:59:59Z"`. */
1545
2434
  expiresAt?: string;
1546
- /** Superadmin only: create a global API key with no tenant (full PBX control) */
2435
+ /** Superadmin only: create a global API key with no tenant (full PBX control). */
1547
2436
  global?: boolean;
1548
- /** Superadmin only: specify which tenant this key belongs to */
2437
+ /** Superadmin only: specify which tenant this key belongs to. */
1549
2438
  tenantId?: string;
1550
2439
  }
1551
2440
  export interface UpdateApiKeyParams {
@@ -1607,17 +2496,201 @@ export interface VoIPClientConfig {
1607
2496
  /** Request timeout in ms (default 15000) */
1608
2497
  timeout?: number;
1609
2498
  }
2499
+ /**
2500
+ * A participant in a three-way conference.
2501
+ *
2502
+ * Each participant is identified by their FreeSWITCH channel UUID (`uuid`)
2503
+ * and their conference member ID (`memberId`). Use `memberId` for mute/kick
2504
+ * operations, and `uuid` for swap/merge operations.
2505
+ *
2506
+ * **Status:** `'active'` = in conference and talking. `'held'` = kicked out
2507
+ * of the conference and placed on hold (hears music). Swapping toggles these.
2508
+ */
1610
2509
  export interface ThreeWayParticipant {
1611
- /** FreeSWITCH channel UUID of this leg */
2510
+ /** FreeSWITCH channel UUID of this leg. Use for swap operations (`keepUuid`/`holdUuid` in `swapParticipant()`). Example: `"a1b2c3d4-..."`. */
1612
2511
  uuid: string;
1613
- /** FreeSWITCH conference member ID (needed for kick/mute) */
2512
+ /** FreeSWITCH conference member ID (integer). Use for mute/kick operations within the conference. Example: `"1"`. */
1614
2513
  memberId: string;
2514
+ /** Caller ID number of this participant. Example: `"+17865551234"` or `"1002"`. */
1615
2515
  callerIdNumber: string;
2516
+ /** Caller ID name of this participant. Example: `"John Smith"`. */
1616
2517
  callerIdName: string;
2518
+ /** Whether this participant is muted in the conference. */
1617
2519
  muted: boolean;
1618
- /** 'active' = in conference, 'held' = kicked out and on hold */
2520
+ /** `'active'` = in conference, `'held'` = kicked out and on hold (hears music). */
1619
2521
  status: 'active' | 'held';
1620
2522
  }
2523
+ /**
2524
+ * State machine for a three-way call session.
2525
+ *
2526
+ * ## Lifecycle
2527
+ *
2528
+ * ```
2529
+ * [Call A active] → addCallParticipant(...)
2530
+ * → adding (hold A, dialing B, waiting for answer)
2531
+ * → [B answers] → mergeCalls(...)
2532
+ * → active (all three in conference)
2533
+ * → swapParticipant(keep, hold) → swapping → active
2534
+ * → kickParticipant(...)
2535
+ * → [caller hangs up] → conference auto-destroys
2536
+ * ```
2537
+ *
2538
+ * ## Key fields
2539
+ *
2540
+ * - `conferenceName`: The FreeSWITCH conference room name. Needed for swap/kick operations.
2541
+ * - `state`: Current phase of the three-way call.
2542
+ * - `pendingUuid`: UUID of Person B's leg while dialing (before merge). `null` after merge.
2543
+ * - `originalBridgedLeg`: UUID of Person A's PSTN bridge leg. Needed to merge correctly.
2544
+ *
2545
+ * @example
2546
+ * ```ts
2547
+ * // Listen for three-way session state
2548
+ * voip.on('threeWayUpdate', (session: ThreeWaySession) => {
2549
+ * if (session.state === 'active') {
2550
+ * console.log('Three-way conference active:', session.conferenceName);
2551
+ * session.participants.forEach(p => {
2552
+ * console.log(` ${p.callerIdNumber} (${p.status}) muted=${p.muted}`);
2553
+ * });
2554
+ * }
2555
+ * });
2556
+ * ```
2557
+ */
2558
+ export interface ThreeWaySession {
2559
+ /** FreeSWITCH conference room name. Pass to `swapParticipant()`, `kickParticipant()`, `endConference()`. Example: `"conf_abc123"`. */
2560
+ conferenceName: string;
2561
+ /** Current state of the three-way session. Use for UI state: show "Adding participant..." during `'adding'`, show participant list during `'active'`. */
2562
+ state: ThreeWayState;
2563
+ /** List of participants currently in the conference. */
2564
+ participants: ThreeWayParticipant[];
2565
+ /** UUID of the second call leg while dialing (before merge). `null` after successful merge or if no pending dial. */
2566
+ pendingUuid?: string;
2567
+ /** UUID of the bridged PSTN leg of the original call. Required for correct merge — returned by `addCallParticipant()`. `null` if the original call had no bridged PSTN leg. */
2568
+ originalBridgedLeg?: string;
2569
+ }
2570
+ /**
2571
+ * Parameters for adding a participant to an active call (first step of three-way calling).
2572
+ *
2573
+ * Provide either `toNumber` (external PSTN) or `toExtension` (internal extension),
2574
+ * but not both. The active call is placed on hold while dialing the new party.
2575
+ *
2576
+ * On success, you receive `newCallUuid` (the new leg's UUID) and `originalBridgedLeg`
2577
+ * (the original call's bridged PSTN leg UUID). Pass both to `mergeCalls()`.
2578
+ *
2579
+ * @example
2580
+ * ```ts
2581
+ * // Add external participant
2582
+ * const { newCallUuid, originalBridgedLeg } = await voip.addCallParticipant(callUuid, {
2583
+ * toNumber: '+17865559999',
2584
+ * });
2585
+ *
2586
+ * // Add internal extension
2587
+ * const { newCallUuid } = await voip.addCallParticipant(callUuid, {
2588
+ * toExtension: '1002',
2589
+ * });
2590
+ * ```
2591
+ */
2592
+ export interface AddParticipantParams {
2593
+ /** PSTN number to call in E.164 format. Example: `"+17865559999"`. */
2594
+ toNumber?: string;
2595
+ /** Internal extension to add. Example: `"1002"`. */
2596
+ toExtension?: string;
2597
+ }
2598
+ /**
2599
+ * Response from `addCallParticipant()`.
2600
+ *
2601
+ * Use `newCallUuid` and `originalBridgedLeg` in the subsequent `mergeCalls()` call
2602
+ * to join all three parties into a conference.
2603
+ */
2604
+ export interface AddParticipantResponse {
2605
+ /** Human-readable message. Example: `"Second call (UUID xxx) established — ready to merge"`. */
2606
+ message: string;
2607
+ /** FreeSWITCH channel UUID of the new call leg (Person B). Pass as `callUuidB` to `mergeCalls()`. */
2608
+ newCallUuid: string;
2609
+ /** FreeSWITCH channel UUID of the original call's bridged PSTN leg. Pass as `bridgedLegA` to `mergeCalls()` for correct merging. */
2610
+ originalBridgedLeg: string;
2611
+ }
2612
+ /**
2613
+ * Parameters for merging two calls into a three-way conference (second step).
2614
+ *
2615
+ * After `addCallParticipant()` succeeds, call `mergeCalls()` with the UUIDs to
2616
+ * join Person A, Person B, and the original PSTN caller into one conference.
2617
+ *
2618
+ * @example
2619
+ * ```ts
2620
+ * const result = await voip.mergeCalls({
2621
+ * callUuidA: activeCall.uuid, // User's WebRTC session
2622
+ * callUuidB: addResult.newCallUuid, // New call leg from addCallParticipant
2623
+ * bridgedLegA: addResult.originalBridgedLeg, // Original PSTN leg
2624
+ * });
2625
+ * console.log('Conference created:', result.conferenceName);
2626
+ * ```
2627
+ */
2628
+ export interface MergeCallsParams {
2629
+ /** UUID of the user's WebRTC session (first call). Use `WebRTCCallInfo.fsChannelUuid`. */
2630
+ callUuidA: string;
2631
+ /** UUID returned by addCallParticipant (Person B's direct channel). */
2632
+ callUuidB: string;
2633
+ /**
2634
+ * Person A's PSTN leg UUID — returned as `originalBridgedLeg` by addCallParticipant.
2635
+ * Passing this avoids an extra ESL lookup and ensures the correct leg is used.
2636
+ */
2637
+ bridgedLegA?: string;
2638
+ /** Optional custom conference name — auto-generated if omitted. */
2639
+ conferenceName?: string;
2640
+ }
2641
+ /**
2642
+ * Response from `mergeCalls()`.
2643
+ *
2644
+ * Contains the conference name (needed for swap/kick/end operations) and the
2645
+ * full participant list with UUIDs, caller IDs, and mute/held status.
2646
+ */
2647
+ export interface MergeCallsResponse {
2648
+ /** Human-readable message. Example: `"Calls merged into conference conf_abc123"`. */
2649
+ message: string;
2650
+ /** FreeSWITCH conference room name. Store this for subsequent swap/kick/end operations. */
2651
+ conferenceName: string;
2652
+ /** List of all participants now in the conference. Use for rendering participant cards in the UI. */
2653
+ participants: ThreeWayParticipant[];
2654
+ }
2655
+ /**
2656
+ * Parameters for directly merging two active WebRTC calls (no PSTN party).
2657
+ *
2658
+ * Use this when the user has two WebRTC calls active simultaneously (e.g.
2659
+ * call on line 1 and line 2) and wants to merge them directly.
2660
+ *
2661
+ * Unlike `addCallParticipant` → `mergeCalls`, this doesn't need a bridged leg UUID
2662
+ * because both calls are WebRTC (no PSTN bridge).
2663
+ *
2664
+ * @example
2665
+ * ```ts
2666
+ * const result = await voip.mergeDirectCalls({
2667
+ * callUuidA: call1.fsChannelUuid,
2668
+ * callUuidB: call2.fsChannelUuid,
2669
+ * });
2670
+ * ```
2671
+ */
2672
+ export interface MergeDirectParams {
2673
+ /** UUID of the first call (WebRTC leg). Use `WebRTCCallInfo.fsChannelUuid`. */
2674
+ callUuidA: string;
2675
+ /** UUID of the second call to merge (WebRTC leg). Use `WebRTCCallInfo.fsChannelUuid`. */
2676
+ callUuidB: string;
2677
+ /** Optional custom conference name — auto-generated if omitted. */
2678
+ conferenceName?: string;
2679
+ }
2680
+ /**
2681
+ * Response from `mergeDirectCalls()`.
2682
+ *
2683
+ * Same structure as `MergeCallsResponse`. All participants are now in the
2684
+ * named conference and can be swapped/kicked independently.
2685
+ */
2686
+ export interface MergeDirectResponse {
2687
+ /** Human-readable message. Example: `"Calls merged into conference conf_abc123"`. */
2688
+ message: string;
2689
+ /** FreeSWITCH conference room name. Store for subsequent operations. */
2690
+ conferenceName: string;
2691
+ /** List of all participants now in the conference. */
2692
+ participants: ThreeWayParticipant[];
2693
+ }
1621
2694
  export type ThreeWayState = 'adding' | 'active' | 'swapping';
1622
2695
  export interface ThreeWaySession {
1623
2696
  conferenceName: string;
@@ -1740,7 +2813,25 @@ export interface AiAgentListResponse {
1740
2813
  agents: AiAgent[];
1741
2814
  total: number;
1742
2815
  }
2816
+ /**
2817
+ * Response containing a single AI agent.
2818
+ *
2819
+ * Returned by `createAiAgent()`, `getAiAgent()`, and `updateAiAgent()`.
2820
+ * The `agent` field contains the full agent configuration from the AI Bridge.
2821
+ *
2822
+ * @example
2823
+ * ```ts
2824
+ * const { agent } = await voip.createAiAgent({
2825
+ * agent_id: 'acme-sales',
2826
+ * display_name: 'Sofia',
2827
+ * voice: 'Aoede',
2828
+ * tools: ['transfer_to_human', 'end_call'],
2829
+ * });
2830
+ * console.log(`Agent "${agent.display_name}" (${agent.agent_id}) created`);
2831
+ * ```
2832
+ */
1743
2833
  export interface AiAgentResponse {
2834
+ /** The full AI agent object from the AI Bridge. */
1744
2835
  agent: AiAgent;
1745
2836
  }
1746
2837
  export interface AiBridgeHealthResponse {
@@ -1920,32 +3011,81 @@ export interface AiCallHistoryResponse {
1920
3011
  calls: AiCallRecord[];
1921
3012
  total: number;
1922
3013
  }
3014
+ /**
3015
+ * A paging group for one-way audio broadcast (intercom/PA system).
3016
+ *
3017
+ * When someone dials `extension_code` (e.g. `*801`), all online members auto-answer
3018
+ * and hear the caller through their speaker. This is a one-way broadcast — members
3019
+ * hear the caller but cannot speak back.
3020
+ *
3021
+ * @example
3022
+ * ```ts
3023
+ * const { pagingGroups } = await voip.listPagingGroups();
3024
+ * pagingGroups.forEach(pg => {
3025
+ * console.log(`${pg.name} (${pg.extension_code}): ${pg.members.length} members`);
3026
+ * });
3027
+ * ```
3028
+ */
1923
3029
  export interface PagingGroup {
3030
+ /** Database UUID of the paging group. */
1924
3031
  id: string;
3032
+ /** Tenant UUID. */
1925
3033
  tenant_id: string;
3034
+ /** Human-readable name. Example: `"All users"`. */
1926
3035
  name: string;
3036
+ /** Optional description. `null` if not set. */
1927
3037
  description: string | null;
3038
+ /** Dial code to trigger paging (e.g. `"*801"`). Must start with `*8`. Unique per tenant. */
1928
3039
  extension_code: string;
3040
+ /** Group status: `'active'` or `'disabled'`. */
1929
3041
  status: string;
3042
+ /** ISO 8601 timestamp of creation. */
1930
3043
  created_at: string;
3044
+ /** ISO 8601 timestamp of last update. */
1931
3045
  updated_at: string;
3046
+ /** List of extension numbers that are members of this paging group. */
1932
3047
  members: PagingGroupMember[];
3048
+ /** Tenant summary — present when queried as global superadmin. */
1933
3049
  tenant?: {
1934
3050
  id: string;
1935
3051
  company_name: string;
1936
3052
  subdomain: string;
1937
3053
  };
1938
3054
  }
3055
+ /**
3056
+ * A member extension within a paging group.
3057
+ */
1939
3058
  export interface PagingGroupMember {
3059
+ /** Database UUID of this member entry. */
1940
3060
  id: string;
3061
+ /** Parent paging group UUID. */
1941
3062
  paging_group_id: string;
3063
+ /** Extension number. Example: `"1001"`. */
1942
3064
  extension: string;
3065
+ /** ISO 8601 timestamp when this member was added. */
1943
3066
  created_at: string;
1944
3067
  }
3068
+ /**
3069
+ * Parameters for creating a new paging group with members.
3070
+ *
3071
+ * @example
3072
+ * ```ts
3073
+ * await voip.createPagingGroup({
3074
+ * name: 'Sales Floor',
3075
+ * description: 'Broadcast to all sales agents',
3076
+ * extensionCode: '*802',
3077
+ * members: [{ extension: '1001' }, { extension: '1002' }, { extension: '1005' }],
3078
+ * });
3079
+ * ```
3080
+ */
1945
3081
  export interface CreatePagingGroupParams {
3082
+ /** Human-readable group name. Example: `"Sales Floor"`. Must be unique within the tenant. */
1946
3083
  name: string;
3084
+ /** Optional description of the group's purpose. */
1947
3085
  description?: string;
3086
+ /** Dial code to activate paging (e.g. `"*802"`). Must start with `*8` and be unique within the tenant. */
1948
3087
  extensionCode: string;
3088
+ /** Array of extensions to include as members. Each entry requires `extension` field. */
1949
3089
  members: {
1950
3090
  extension: string;
1951
3091
  }[];