@unboundcx/sdk 4.13.98 → 4.13.99

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.99",
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,80 @@ 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 for a voice task in 'callback' mode hands the customer
447
+ * off to the existing queue-wait callback contract (hangs up, task goes
448
+ * pending, human accept later auto-dials the customer back).
449
+ *
450
+ * @param {Object} options - Parameters
451
+ * @param {string} options.taskId - The task ID to release (required)
452
+ * @param {'live'|'callback'} [options.mode] - Required for a voice task (has a live call); ignored for a digital task
453
+ * @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'
454
+ * @param {string} options.reason - One-sentence reason shown to the next agent (required)
455
+ * @param {string} [options.callbackNumber] - E.164 callback number ('callback' mode only; defaults to the task's `from`)
456
+ * @param {boolean} [options.humanOnly=true] - Stamp botEligible:false so only a human is offered this task
457
+ * @param {boolean} [options.hangup=true] - Hang up the customer leg ('callback' mode only)
458
+ * @returns {Promise<Object>} { taskId, status: 'pending', mode, humanOnly, reasonCode }
459
+ *
460
+ * @example
461
+ * // Caller confirmed a callback -- release and hang up
462
+ * await sdk.taskRouter.task.release({
463
+ * taskId: 'task123',
464
+ * mode: 'callback',
465
+ * reasonCode: 'callback_promised',
466
+ * reason: 'Caller asked for a callback once an agent frees up',
467
+ * });
468
+ *
469
+ * @example
470
+ * // Caller wants to hold for a human -- release, keep the call live
471
+ * await sdk.taskRouter.task.release({
472
+ * taskId: 'task123',
473
+ * mode: 'live',
474
+ * reasonCode: 'no_human_available',
475
+ * reason: 'No agents available, caller chose to hold',
476
+ * });
477
+ */
478
+ async release(options = {}) {
479
+ const {
480
+ taskId,
481
+ mode,
482
+ reasonCode,
483
+ reason,
484
+ callbackNumber,
485
+ humanOnly,
486
+ hangup,
487
+ } = options;
488
+
489
+ this.sdk.validateParams(
490
+ { taskId, mode, reasonCode, reason, callbackNumber, humanOnly, hangup },
491
+ {
492
+ taskId: { type: 'string', required: true },
493
+ mode: { type: 'string', required: false },
494
+ reasonCode: { type: 'string', required: true },
495
+ reason: { type: 'string', required: true },
496
+ callbackNumber: { type: 'string', required: false },
497
+ humanOnly: { type: 'boolean', required: false },
498
+ hangup: { type: 'boolean', required: false },
499
+ },
500
+ );
501
+
502
+ const params = { body: { taskId, reasonCode, reason } };
503
+ if (mode !== undefined) params.body.mode = mode;
504
+ if (callbackNumber !== undefined) params.body.callbackNumber = callbackNumber;
505
+ if (humanOnly !== undefined) params.body.humanOnly = humanOnly;
506
+ if (hangup !== undefined) params.body.hangup = hangup;
507
+
508
+ return await internalRequest(
509
+ this.sdk,
510
+ '/taskRouter/tasks/release',
511
+ 'PUT',
512
+ params,
513
+ );
514
+ }
515
+
442
516
  /**
443
517
  * Staff-only internal note on a task (webchat/SMS/voice feed, or
444
518
  * timeline). Never sent to the customer.
@@ -871,6 +945,8 @@ export class TaskService {
871
945
  * @param {string} [options.subject] - The new subject/title for the task
872
946
  * @param {string} [options.summary] - The overall summary for the task
873
947
  * @param {string} [options.disposition] - The disposition code or outcome for the task (e.g., 'resolved', 'escalated', 'callback-scheduled')
948
+ * @param {boolean} [options.botEligible] - Routing flag. `false` = never offer this task to bot workers (human only); `true` re-allows bots
949
+ * @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
950
  * @returns {Promise<Object>} Object containing the task ID
875
951
  * @returns {string} result.taskId - The task ID that was updated
876
952
  *
@@ -898,6 +974,10 @@ export class TaskService {
898
974
  * disposition: 'escalated'
899
975
  * });
900
976
  * console.log(result.taskId); // "task789"
977
+ *
978
+ * @example
979
+ * // Human-only routing: bot workers are no longer offered this task
980
+ * await sdk.taskRouter.task.update({ taskId: 'task789', botEligible: false });
901
981
  */
902
982
  async update(options = {}) {
903
983
  const {
@@ -908,10 +988,22 @@ export class TaskService {
908
988
  cdrId,
909
989
  summary,
910
990
  sentiment,
991
+ botEligible,
992
+ humanFollowUp,
911
993
  } = options;
912
994
 
913
995
  this.sdk.validateParams(
914
- { taskId, subject, disposition, sipCallId, cdrId, summary, sentiment },
996
+ {
997
+ taskId,
998
+ subject,
999
+ disposition,
1000
+ sipCallId,
1001
+ cdrId,
1002
+ summary,
1003
+ sentiment,
1004
+ botEligible,
1005
+ humanFollowUp,
1006
+ },
915
1007
  {
916
1008
  taskId: { type: 'string', required: true },
917
1009
  subject: { type: 'string', required: false },
@@ -920,6 +1012,10 @@ export class TaskService {
920
1012
  sipCallId: { type: 'string', required: false },
921
1013
  summary: { type: 'string', required: false },
922
1014
  sentiment: { type: 'object', required: false },
1015
+ botEligible: { type: 'boolean', required: false },
1016
+ // validateParams already skips type-checking a null value (see
1017
+ // base.js) -- 'string' here only constrains the non-null case.
1018
+ humanFollowUp: { type: 'string', required: false },
923
1019
  },
924
1020
  );
925
1021
 
@@ -929,6 +1025,14 @@ export class TaskService {
929
1025
  },
930
1026
  };
931
1027
 
1028
+ if (botEligible !== undefined) {
1029
+ params.body.botEligible = botEligible;
1030
+ }
1031
+
1032
+ if (humanFollowUp !== undefined) {
1033
+ params.body.humanFollowUp = humanFollowUp;
1034
+ }
1035
+
932
1036
  if (subject !== undefined) {
933
1037
  params.body.subject = subject;
934
1038
  }
@@ -1141,22 +1245,37 @@ export class TaskService {
1141
1245
  * @param {string} [options.target.queueId] - Destination queue ID
1142
1246
  * @param {string} [options.target.workerId] - Destination worker ID
1143
1247
  * @param {string} [options.note] - Optional note for the receiving agent
1248
+ * @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.
1249
+ * @param {string} [options.reason] - One-sentence transfer reason. Required when the caller's worker is a bot.
1144
1250
  * @returns {Promise<Object>} { taskId, newTaskId }
1251
+ *
1252
+ * @example
1253
+ * // Bot transferring to a configured queue target
1254
+ * await sdk.taskRouter.task.transfer({
1255
+ * taskId: 'task123',
1256
+ * target: { queueId: 'billingQueue1' },
1257
+ * reasonCode: 'wrong_department',
1258
+ * reason: 'Caller has a billing question',
1259
+ * });
1145
1260
  */
1146
1261
  async transfer(options = {}) {
1147
- const { taskId, target, note } = options;
1262
+ const { taskId, target, note, reasonCode, reason } = options;
1148
1263
 
1149
1264
  this.sdk.validateParams(
1150
- { taskId, target, note },
1265
+ { taskId, target, note, reasonCode, reason },
1151
1266
  {
1152
1267
  taskId: { type: 'string', required: true },
1153
1268
  target: { type: 'object', required: true },
1154
1269
  note: { type: 'string', required: false },
1270
+ reasonCode: { type: 'string', required: false },
1271
+ reason: { type: 'string', required: false },
1155
1272
  },
1156
1273
  );
1157
1274
 
1158
1275
  const params = { body: { taskId, target } };
1159
1276
  if (note !== undefined) params.body.note = note;
1277
+ if (reasonCode !== undefined) params.body.reasonCode = reasonCode;
1278
+ if (reason !== undefined) params.body.reason = reason;
1160
1279
 
1161
1280
  return await internalRequest(
1162
1281
  this.sdk,