@unboundcx/sdk 4.13.98 → 4.13.100

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@unboundcx/sdk",
3
- "version": "4.13.98",
3
+ "version": "4.13.100",
4
4
  "description": "Official JavaScript SDK for the Unbound API - A comprehensive toolkit for integrating with Unbound's communication, AI, and data management services",
5
5
  "main": "index.js",
6
6
  "type": "module",
@@ -439,6 +439,82 @@ export class TaskService {
439
439
  );
440
440
  }
441
441
 
442
+ /**
443
+ * Release a task back to the queue for a human (same queue, same task
444
+ * id) — the bot-task-lifecycle release contract. Stamps
445
+ * botEligible:false (when humanOnly) plus named release-reason
446
+ * metadata and keeps the customer's original place in line. Voice:
447
+ * 'live' keeps the call on hold music for the next human; 'callback'
448
+ * ends the call and the task's primary channel becomes whatever is still
449
+ * live (e.g. sms) — the human who accepts follows up like on any task.
450
+ * This is not the queue-wait callback feature (no auto-dial).
451
+ *
452
+ * @param {Object} options - Parameters
453
+ * @param {string} options.taskId - The task ID to release (required)
454
+ * @param {'live'|'callback'} [options.mode] - Required for a voice task (has a live call); ignored for a digital task
455
+ * @param {string} options.reasonCode - Release reason code (required) — e.g. 'callback_promised', 'human_requested', 'no_human_available', 'bot_cannot_resolve', 'customer_frustrated', 'review_failed', 'policy_human_only', 'other'
456
+ * @param {string} options.reason - One-sentence reason shown to the next agent (required)
457
+ * @param {string} [options.callbackNumber] - E.164 callback number ('callback' mode only; defaults to the task's `from`)
458
+ * @param {boolean} [options.humanOnly=true] - Stamp botEligible:false so only a human is offered this task
459
+ * @param {boolean} [options.hangup=true] - Hang up the customer leg ('callback' mode only)
460
+ * @returns {Promise<Object>} { taskId, status: 'pending', mode, humanOnly, reasonCode }
461
+ *
462
+ * @example
463
+ * // Caller confirmed a callback -- release and hang up
464
+ * await sdk.taskRouter.task.release({
465
+ * taskId: 'task123',
466
+ * mode: 'callback',
467
+ * reasonCode: 'callback_promised',
468
+ * reason: 'Caller asked for a callback once an agent frees up',
469
+ * });
470
+ *
471
+ * @example
472
+ * // Caller wants to hold for a human -- release, keep the call live
473
+ * await sdk.taskRouter.task.release({
474
+ * taskId: 'task123',
475
+ * mode: 'live',
476
+ * reasonCode: 'no_human_available',
477
+ * reason: 'No agents available, caller chose to hold',
478
+ * });
479
+ */
480
+ async release(options = {}) {
481
+ const {
482
+ taskId,
483
+ mode,
484
+ reasonCode,
485
+ reason,
486
+ callbackNumber,
487
+ humanOnly,
488
+ hangup,
489
+ } = options;
490
+
491
+ this.sdk.validateParams(
492
+ { taskId, mode, reasonCode, reason, callbackNumber, humanOnly, hangup },
493
+ {
494
+ taskId: { type: 'string', required: true },
495
+ mode: { type: 'string', required: false },
496
+ reasonCode: { type: 'string', required: true },
497
+ reason: { type: 'string', required: true },
498
+ callbackNumber: { type: 'string', required: false },
499
+ humanOnly: { type: 'boolean', required: false },
500
+ hangup: { type: 'boolean', required: false },
501
+ },
502
+ );
503
+
504
+ const params = { body: { taskId, reasonCode, reason } };
505
+ if (mode !== undefined) params.body.mode = mode;
506
+ if (callbackNumber !== undefined) params.body.callbackNumber = callbackNumber;
507
+ if (humanOnly !== undefined) params.body.humanOnly = humanOnly;
508
+ if (hangup !== undefined) params.body.hangup = hangup;
509
+
510
+ return await internalRequest(
511
+ this.sdk,
512
+ '/taskRouter/tasks/release',
513
+ 'PUT',
514
+ params,
515
+ );
516
+ }
517
+
442
518
  /**
443
519
  * Staff-only internal note on a task (webchat/SMS/voice feed, or
444
520
  * timeline). Never sent to the customer.
@@ -871,6 +947,8 @@ export class TaskService {
871
947
  * @param {string} [options.subject] - The new subject/title for the task
872
948
  * @param {string} [options.summary] - The overall summary for the task
873
949
  * @param {string} [options.disposition] - The disposition code or outcome for the task (e.g., 'resolved', 'escalated', 'callback-scheduled')
950
+ * @param {boolean} [options.botEligible] - Routing flag. `false` = never offer this task to bot workers (human only); `true` re-allows bots
951
+ * @param {?string} [options.humanFollowUp] - What a human still owes this customer: 'callback' | 'message' | 'dispatch' | 'quote' | 'other', or null to clear. Read by the caller-hangup safety net so an abandoned call with this set releases to the queue instead of completing.
874
952
  * @returns {Promise<Object>} Object containing the task ID
875
953
  * @returns {string} result.taskId - The task ID that was updated
876
954
  *
@@ -898,6 +976,10 @@ export class TaskService {
898
976
  * disposition: 'escalated'
899
977
  * });
900
978
  * console.log(result.taskId); // "task789"
979
+ *
980
+ * @example
981
+ * // Human-only routing: bot workers are no longer offered this task
982
+ * await sdk.taskRouter.task.update({ taskId: 'task789', botEligible: false });
901
983
  */
902
984
  async update(options = {}) {
903
985
  const {
@@ -908,10 +990,22 @@ export class TaskService {
908
990
  cdrId,
909
991
  summary,
910
992
  sentiment,
993
+ botEligible,
994
+ humanFollowUp,
911
995
  } = options;
912
996
 
913
997
  this.sdk.validateParams(
914
- { taskId, subject, disposition, sipCallId, cdrId, summary, sentiment },
998
+ {
999
+ taskId,
1000
+ subject,
1001
+ disposition,
1002
+ sipCallId,
1003
+ cdrId,
1004
+ summary,
1005
+ sentiment,
1006
+ botEligible,
1007
+ humanFollowUp,
1008
+ },
915
1009
  {
916
1010
  taskId: { type: 'string', required: true },
917
1011
  subject: { type: 'string', required: false },
@@ -920,6 +1014,10 @@ export class TaskService {
920
1014
  sipCallId: { type: 'string', required: false },
921
1015
  summary: { type: 'string', required: false },
922
1016
  sentiment: { type: 'object', required: false },
1017
+ botEligible: { type: 'boolean', required: false },
1018
+ // validateParams already skips type-checking a null value (see
1019
+ // base.js) -- 'string' here only constrains the non-null case.
1020
+ humanFollowUp: { type: 'string', required: false },
923
1021
  },
924
1022
  );
925
1023
 
@@ -929,6 +1027,14 @@ export class TaskService {
929
1027
  },
930
1028
  };
931
1029
 
1030
+ if (botEligible !== undefined) {
1031
+ params.body.botEligible = botEligible;
1032
+ }
1033
+
1034
+ if (humanFollowUp !== undefined) {
1035
+ params.body.humanFollowUp = humanFollowUp;
1036
+ }
1037
+
932
1038
  if (subject !== undefined) {
933
1039
  params.body.subject = subject;
934
1040
  }
@@ -1141,22 +1247,37 @@ export class TaskService {
1141
1247
  * @param {string} [options.target.queueId] - Destination queue ID
1142
1248
  * @param {string} [options.target.workerId] - Destination worker ID
1143
1249
  * @param {string} [options.note] - Optional note for the receiving agent
1250
+ * @param {string} [options.reasonCode] - Transfer reason code — e.g. 'wrong_department', 'customer_requested', 'out_of_scope', 'policy_never_bot', 'language', 'other'. Required when the caller's worker is a bot.
1251
+ * @param {string} [options.reason] - One-sentence transfer reason. Required when the caller's worker is a bot.
1144
1252
  * @returns {Promise<Object>} { taskId, newTaskId }
1253
+ *
1254
+ * @example
1255
+ * // Bot transferring to a configured queue target
1256
+ * await sdk.taskRouter.task.transfer({
1257
+ * taskId: 'task123',
1258
+ * target: { queueId: 'billingQueue1' },
1259
+ * reasonCode: 'wrong_department',
1260
+ * reason: 'Caller has a billing question',
1261
+ * });
1145
1262
  */
1146
1263
  async transfer(options = {}) {
1147
- const { taskId, target, note } = options;
1264
+ const { taskId, target, note, reasonCode, reason } = options;
1148
1265
 
1149
1266
  this.sdk.validateParams(
1150
- { taskId, target, note },
1267
+ { taskId, target, note, reasonCode, reason },
1151
1268
  {
1152
1269
  taskId: { type: 'string', required: true },
1153
1270
  target: { type: 'object', required: true },
1154
1271
  note: { type: 'string', required: false },
1272
+ reasonCode: { type: 'string', required: false },
1273
+ reason: { type: 'string', required: false },
1155
1274
  },
1156
1275
  );
1157
1276
 
1158
1277
  const params = { body: { taskId, target } };
1159
1278
  if (note !== undefined) params.body.note = note;
1279
+ if (reasonCode !== undefined) params.body.reasonCode = reasonCode;
1280
+ if (reason !== undefined) params.body.reason = reason;
1160
1281
 
1161
1282
  return await internalRequest(
1162
1283
  this.sdk,