@unboundcx/sdk 4.13.97 → 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 +1 -1
- package/services/ai/tts.js +155 -0
- package/services/ai.js +1 -73
- package/services/taskRouter/TaskService.js +122 -3
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@unboundcx/sdk",
|
|
3
|
-
"version": "4.13.
|
|
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",
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { internalRequest } from '../../base.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Text-to-speech. `sdk.ai.tts.*`.
|
|
5
|
+
*
|
|
6
|
+
* @see app1-api src/services/ai/routes/tts.js
|
|
7
|
+
*/
|
|
8
|
+
export class TextToSpeechService {
|
|
9
|
+
constructor(sdk) {
|
|
10
|
+
this.sdk = sdk;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Render text to speech and get back a storage id/url (buffered — waits
|
|
15
|
+
* for the whole file). For low-latency playback (e.g. a voice bot) use
|
|
16
|
+
* `stream()` instead.
|
|
17
|
+
* @param {Object} params
|
|
18
|
+
* @param {string} params.text
|
|
19
|
+
* @param {string} [params.voice]
|
|
20
|
+
* @param {string} [params.languageCode]
|
|
21
|
+
* @param {string} [params.ssmlGender]
|
|
22
|
+
* @param {string} [params.audioEncoding]
|
|
23
|
+
* @param {number} [params.speakingRate]
|
|
24
|
+
* @param {number} [params.pitch]
|
|
25
|
+
* @param {number} [params.volumeGainDb]
|
|
26
|
+
* @param {string[]} [params.effectsProfileIds]
|
|
27
|
+
* @param {boolean} [params.createAccessKey]
|
|
28
|
+
* @returns {Promise<Object>} `{ id, storageId, url? }`
|
|
29
|
+
*/
|
|
30
|
+
async create({
|
|
31
|
+
text,
|
|
32
|
+
voice,
|
|
33
|
+
languageCode,
|
|
34
|
+
ssmlGender,
|
|
35
|
+
audioEncoding,
|
|
36
|
+
speakingRate,
|
|
37
|
+
pitch,
|
|
38
|
+
volumeGainDb,
|
|
39
|
+
effectsProfileIds,
|
|
40
|
+
createAccessKey,
|
|
41
|
+
}) {
|
|
42
|
+
this.sdk.validateParams(
|
|
43
|
+
{
|
|
44
|
+
text,
|
|
45
|
+
voice,
|
|
46
|
+
languageCode,
|
|
47
|
+
ssmlGender,
|
|
48
|
+
audioEncoding,
|
|
49
|
+
speakingRate,
|
|
50
|
+
pitch,
|
|
51
|
+
volumeGainDb,
|
|
52
|
+
effectsProfileIds,
|
|
53
|
+
createAccessKey,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
text: { type: 'string', required: true },
|
|
57
|
+
voice: { type: 'string', required: false },
|
|
58
|
+
languageCode: { type: 'string', required: false },
|
|
59
|
+
ssmlGender: { type: 'string', required: false },
|
|
60
|
+
audioEncoding: { type: 'string', required: false },
|
|
61
|
+
speakingRate: { type: 'number', required: false },
|
|
62
|
+
pitch: { type: 'number', required: false },
|
|
63
|
+
volumeGainDb: { type: 'number', required: false },
|
|
64
|
+
effectsProfileIds: { type: 'array', required: false },
|
|
65
|
+
createAccessKey: { type: 'boolean', required: false },
|
|
66
|
+
},
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
const ttsData = { text };
|
|
70
|
+
if (voice) ttsData.voice = voice;
|
|
71
|
+
if (languageCode) ttsData.languageCode = languageCode;
|
|
72
|
+
if (ssmlGender) ttsData.ssmlGender = ssmlGender;
|
|
73
|
+
if (audioEncoding) ttsData.audioEncoding = audioEncoding;
|
|
74
|
+
if (speakingRate) ttsData.speakingRate = speakingRate;
|
|
75
|
+
if (pitch) ttsData.pitch = pitch;
|
|
76
|
+
if (volumeGainDb) ttsData.volumeGainDb = volumeGainDb;
|
|
77
|
+
if (effectsProfileIds) ttsData.effectsProfileIds = effectsProfileIds;
|
|
78
|
+
if (createAccessKey) ttsData.createAccessKey = createAccessKey;
|
|
79
|
+
|
|
80
|
+
const params = {
|
|
81
|
+
body: ttsData,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const result = await internalRequest(this.sdk, '/ai/tts', 'POST', params);
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* List available TTS voices
|
|
90
|
+
* @returns {Promise<Object>} { voices: Array, count: number, supportedEncodings: Array, supportedLanguages: Array }
|
|
91
|
+
*/
|
|
92
|
+
async list() {
|
|
93
|
+
const result = await internalRequest(this.sdk, '/ai/tts', 'GET');
|
|
94
|
+
return result;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Stream TTS audio as it's generated — first bytes can arrive well before
|
|
99
|
+
* the whole utterance finishes rendering (Groq voices: TTFB ~0.2s).
|
|
100
|
+
* Always renders wav; shares its cache with `create()` when
|
|
101
|
+
* audioEncoding:'wav' is used there.
|
|
102
|
+
*
|
|
103
|
+
* Node: wrap the result in `Readable.fromWeb(result.body)` to get a
|
|
104
|
+
* normal Node stream (e.g. to pipe into ffmpeg). Browser: `result.body`
|
|
105
|
+
* is already a web ReadableStream you can read directly or hand to
|
|
106
|
+
* `new Response(result.body)` / a `<audio>` element via a Blob.
|
|
107
|
+
*
|
|
108
|
+
* Response headers of note: `x-tts-cache` (`hit`|`miss`) and `x-tts-id`
|
|
109
|
+
* (set on a cache hit, when the id is already known).
|
|
110
|
+
*
|
|
111
|
+
* @param {Object} params
|
|
112
|
+
* @param {string} params.text
|
|
113
|
+
* @param {string} [params.voice]
|
|
114
|
+
* @param {string} [params.languageCode]
|
|
115
|
+
* @returns {Promise<{body: ReadableStream, headers: Headers, status: number}>}
|
|
116
|
+
* @example
|
|
117
|
+
* const result = await sdk.ai.tts.stream({ text: 'Hi there', voice: 'hannah' });
|
|
118
|
+
* const nodeStream = Readable.fromWeb(result.body);
|
|
119
|
+
* nodeStream.pipe(ffmpegProcess.stdin);
|
|
120
|
+
*/
|
|
121
|
+
async stream({ text, voice, languageCode }) {
|
|
122
|
+
this.sdk.validateParams(
|
|
123
|
+
{ text, voice, languageCode },
|
|
124
|
+
{
|
|
125
|
+
text: { type: 'string', required: true },
|
|
126
|
+
voice: { type: 'string', required: false },
|
|
127
|
+
languageCode: { type: 'string', required: false },
|
|
128
|
+
},
|
|
129
|
+
);
|
|
130
|
+
|
|
131
|
+
const ttsData = { text };
|
|
132
|
+
if (voice) ttsData.voice = voice;
|
|
133
|
+
if (languageCode) ttsData.languageCode = languageCode;
|
|
134
|
+
|
|
135
|
+
const params = {
|
|
136
|
+
body: ttsData,
|
|
137
|
+
returnRawResponse: true,
|
|
138
|
+
};
|
|
139
|
+
|
|
140
|
+
// forceFetch: true — NATS transport can't carry a streamed body.
|
|
141
|
+
const response = await internalRequest(
|
|
142
|
+
this.sdk,
|
|
143
|
+
'/ai/tts/stream',
|
|
144
|
+
'POST',
|
|
145
|
+
params,
|
|
146
|
+
true,
|
|
147
|
+
);
|
|
148
|
+
|
|
149
|
+
return {
|
|
150
|
+
body: response.body,
|
|
151
|
+
headers: response.headers,
|
|
152
|
+
status: response.status,
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
package/services/ai.js
CHANGED
|
@@ -5,6 +5,7 @@ import { AssistService } from './ai/assist.js';
|
|
|
5
5
|
import { VocabularyService } from './ai/vocabulary.js';
|
|
6
6
|
import { EmailService } from './ai/email.js';
|
|
7
7
|
import { ModelsService } from './ai/models.js';
|
|
8
|
+
import { TextToSpeechService } from './ai/tts.js';
|
|
8
9
|
import { translate as translateItems } from './ai/translate.js';
|
|
9
10
|
import {
|
|
10
11
|
getSettings as getAiSettings,
|
|
@@ -487,79 +488,6 @@ export class GenerativeService {
|
|
|
487
488
|
// }
|
|
488
489
|
}
|
|
489
490
|
|
|
490
|
-
export class TextToSpeechService {
|
|
491
|
-
constructor(sdk) {
|
|
492
|
-
this.sdk = sdk;
|
|
493
|
-
}
|
|
494
|
-
|
|
495
|
-
async create({
|
|
496
|
-
text,
|
|
497
|
-
voice,
|
|
498
|
-
languageCode,
|
|
499
|
-
ssmlGender,
|
|
500
|
-
audioEncoding,
|
|
501
|
-
speakingRate,
|
|
502
|
-
pitch,
|
|
503
|
-
volumeGainDb,
|
|
504
|
-
effectsProfileIds,
|
|
505
|
-
createAccessKey,
|
|
506
|
-
}) {
|
|
507
|
-
this.sdk.validateParams(
|
|
508
|
-
{
|
|
509
|
-
text,
|
|
510
|
-
voice,
|
|
511
|
-
languageCode,
|
|
512
|
-
ssmlGender,
|
|
513
|
-
audioEncoding,
|
|
514
|
-
speakingRate,
|
|
515
|
-
pitch,
|
|
516
|
-
volumeGainDb,
|
|
517
|
-
effectsProfileIds,
|
|
518
|
-
createAccessKey,
|
|
519
|
-
},
|
|
520
|
-
{
|
|
521
|
-
text: { type: 'string', required: true },
|
|
522
|
-
voice: { type: 'string', required: false },
|
|
523
|
-
languageCode: { type: 'string', required: false },
|
|
524
|
-
ssmlGender: { type: 'string', required: false },
|
|
525
|
-
audioEncoding: { type: 'string', required: false },
|
|
526
|
-
speakingRate: { type: 'number', required: false },
|
|
527
|
-
pitch: { type: 'number', required: false },
|
|
528
|
-
volumeGainDb: { type: 'number', required: false },
|
|
529
|
-
effectsProfileIds: { type: 'array', required: false },
|
|
530
|
-
createAccessKey: { type: 'boolean', required: false },
|
|
531
|
-
},
|
|
532
|
-
);
|
|
533
|
-
|
|
534
|
-
const ttsData = { text };
|
|
535
|
-
if (voice) ttsData.voice = voice;
|
|
536
|
-
if (languageCode) ttsData.languageCode = languageCode;
|
|
537
|
-
if (ssmlGender) ttsData.ssmlGender = ssmlGender;
|
|
538
|
-
if (audioEncoding) ttsData.audioEncoding = audioEncoding;
|
|
539
|
-
if (speakingRate) ttsData.speakingRate = speakingRate;
|
|
540
|
-
if (pitch) ttsData.pitch = pitch;
|
|
541
|
-
if (volumeGainDb) ttsData.volumeGainDb = volumeGainDb;
|
|
542
|
-
if (effectsProfileIds) ttsData.effectsProfileIds = effectsProfileIds;
|
|
543
|
-
if (createAccessKey) ttsData.createAccessKey = createAccessKey;
|
|
544
|
-
|
|
545
|
-
const params = {
|
|
546
|
-
body: ttsData,
|
|
547
|
-
};
|
|
548
|
-
|
|
549
|
-
const result = await internalRequest(this.sdk, '/ai/tts', 'POST', params);
|
|
550
|
-
return result;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
|
-
/**
|
|
554
|
-
* List available TTS voices
|
|
555
|
-
* @returns {Promise<Object>} { voices: Array, count: number, supportedEncodings: Array, supportedLanguages: Array }
|
|
556
|
-
*/
|
|
557
|
-
async list() {
|
|
558
|
-
const result = await internalRequest(this.sdk, '/ai/tts', 'GET');
|
|
559
|
-
return result;
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
|
|
563
491
|
export class SpeechToTextService {
|
|
564
492
|
constructor(sdk) {
|
|
565
493
|
this.sdk = sdk;
|
|
@@ -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
|
-
{
|
|
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,
|