@signalhousellc/sdk 1.0.54 → 1.0.56

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": "@signalhousellc/sdk",
3
- "version": "1.0.54",
3
+ "version": "1.0.56",
4
4
  "description": "Signal House SDK for use with the Signal House platform",
5
5
  "type": "module",
6
6
  "main": "src/SignalHouseSDK.js",
@@ -19,6 +19,7 @@ import { Onboarding } from "./domains/Onboarding.js";
19
19
  import { Shortlinks } from "./domains/Shortlinks.js";
20
20
  import { Subgroups } from "./domains/Subgroups.js";
21
21
  import { Subscriptions } from "./domains/Subscriptions.js";
22
+ import { Tickets } from "./domains/Tickets.js";
22
23
  import { Users } from "./domains/Users.js";
23
24
  import { Notifications } from "./domains/Notifications.js";
24
25
  import { Webhooks } from "./domains/Webhooks.js";
@@ -56,7 +57,7 @@ export class SignalHouseSDK {
56
57
  this.auth = new Auth(client, this.enableAdmin);
57
58
  this.billing = new Billing(client, this.enableAdmin);
58
59
  this.brands = new Brands(client, multipartClient, this.enableAdmin);
59
- this.campaigns = new Campaigns(client, this.enableAdmin);
60
+ this.campaigns = new Campaigns(client, multipartClient, this.enableAdmin);
60
61
  this.groups = new Groups(client, this.enableAdmin);
61
62
  this.landings = new Landings(client, multipartClient, this.enableAdmin);
62
63
  this.messages = new Messages(client, multipartClient, this.enableAdmin);
@@ -65,6 +66,7 @@ export class SignalHouseSDK {
65
66
  this.shortlinks = new Shortlinks(client, this.enableAdmin);
66
67
  this.subgroups = new Subgroups(client, this.enableAdmin);
67
68
  this.subscriptions = new Subscriptions(client, this.enableAdmin);
69
+ this.tickets = new Tickets(client, this.enableAdmin);
68
70
  this.users = new Users(client, this.enableAdmin);
69
71
  this.notifications = new Notifications(client, this.enableAdmin);
70
72
  this.webhooks = new Webhooks(client, this.enableAdmin);
@@ -147,6 +147,19 @@ export class Auth {
147
147
  return this.client(`/auth/logout-all`, { method: "POST", ...options });
148
148
  }
149
149
 
150
+ /**
151
+ * Get the Group ID associated with the caller's JWT (the caller's active group). Useful for
152
+ * discovering your own groupId, which is required on most other API requests.
153
+ * @async
154
+ * @roles admin, developer, billing, user, api
155
+ * @param {Object} [params]
156
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
157
+ * @returns {Promise<Object>} The response containing { groupId }
158
+ */
159
+ async getGroupId({ options = {} } = {}) {
160
+ return this.client(`/auth/group-id`, { method: "GET", ...options });
161
+ }
162
+
150
163
  /**
151
164
  * Mint a single-use, short-lived external-link token for the authenticated caller. The token is
152
165
  * handed to the GHL/Shopify backend so it can link the caller's existing V2 group to its tenant.
@@ -1,3 +1,9 @@
1
+ /**
2
+ * @typedef {string} BrandLookupId - Carrier Brand ID (B… or TFNB…), Mongo `_id`, or internal reference UUID.
3
+ * Use on update, delete, revet, vetting, appeal, and transfer routes. Pending brands return `brandId: null`
4
+ * in read/create responses — poll `GET /brand?id=<Mongo _id>` until a carrier Brand ID is assigned.
5
+ */
6
+
1
7
  /**
2
8
  * @typedef {Object} CreateBrandData
3
9
  * @property {string} subgroupId - The ID of the subgroup to create the brand under
@@ -103,7 +109,7 @@ export class Brands {
103
109
  * @async
104
110
  * @roles api, admin, developer, user
105
111
  * @param {Object} params - The parameters for filtering the brands
106
- * @param {string} [params.id] - The ID of the brand to filter by
112
+ * @param {string} [params.id] - Brand lookup id (carrier Brand ID, Mongo _id, or internal reference)
107
113
  * @param {string} [params.subgroupId] - The ID of the subgroup to filter by
108
114
  * @param {string} [params.groupId] - The ID of the group to filter by
109
115
  * @param {number} [params.page] - The page number for pagination
@@ -111,7 +117,7 @@ export class Brands {
111
117
  * @param {string} [params.status] - The status of the brand to filter by (PENDING_CREATION, PENDING_APPROVAL, UNVERIFIED, VERIFIED, VETTED_VERIFIED, PENDING_DELETE, DELETED)
112
118
  * @param {string} [params.registrationType] - Filter by registration type ("TEN_DLC" or "TOLL_FREE")
113
119
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
114
- * @returns {Promise<Array>} The response from the server
120
+ * @returns {Promise<Array<{ _id: string, brandId: string|null, status: string, registrationType: string, [key: string]: any }>>} Brand records. For 10DLC brands in PENDING_CREATION (or rejected before carrier assignment), brandId is null — poll by _id until status advances and brandId is assigned.
115
121
  */
116
122
  async getBrands({ id, subgroupId, groupId, page, limit, status, registrationType, options = {} }) {
117
123
  const filters = { id, subgroupId, groupId, page, limit, status, registrationType };
@@ -124,7 +130,7 @@ export class Brands {
124
130
  * @async
125
131
  * @roles api, admin, developer, user
126
132
  * @param {Object} params - The parameters for getting the external vetting information
127
- * @param {string} params.brandId - The ID of the brand to get the external vetting information for
133
+ * @param {BrandLookupId} params.brandId - Brand lookup id (carrier Brand ID, Mongo `_id`, or internal reference).
128
134
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
129
135
  * @throws {Error} Throws an error if the brandId parameter is missing
130
136
  * @returns {Promise<Object>} The response from the server
@@ -143,7 +149,7 @@ export class Brands {
143
149
  * @param {CreateBrandData} params.brandData - The data for the brand to be created
144
150
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
145
151
  * @throws {Error} Throws an error if the brandData parameter is missing or if required fields in brandData are missing
146
- * @returns {Promise<Object>} The response from the server
152
+ * @returns {Promise<Object>} Brand entity. `brandId` is `null` until the carrier assigns a Brand ID — use `_id` to poll status.
147
153
  */
148
154
  async createBrand({ brandData, options = {} }) {
149
155
  this.client._require({ brandData: brandData });
@@ -158,7 +164,7 @@ export class Brands {
158
164
  * @param {CreateTollFreeBrandData} params.brandData - The data for the toll-free brand to be created (see CreateTollFreeBrandData typedef for details; TFN-specific fields live under brandData.tollFree, and registrationType is forced server-side by the route)
159
165
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
160
166
  * @throws {Error} Throws an error if the brandData parameter is missing
161
- * @returns {Promise<Object>} The response from the server
167
+ * @returns {Promise<Object>} Brand entity. For Toll-Free, `brandId` is a TFNB-prefixed id when assigned; otherwise `null` — use `_id` to poll.
162
168
  */
163
169
  async createTollFreeBrand({ brandData, options = {} }) {
164
170
  this.client._require({ brandData });
@@ -171,7 +177,7 @@ export class Brands {
171
177
  * @roles api, admin, developer, billing, user
172
178
  * @param {Object} params - The parameters for transferring the brands
173
179
  * @param {string} params.subgroupId - The ID of the subgroup to transfer the brands to
174
- * @param {Array<string>} params.brandIds - The IDs of the brands to be transferred
180
+ * @param {BrandLookupId[]} params.brandIds - Brand lookup ids to transfer (carrier id, Mongo `_id`, or internal reference).
175
181
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
176
182
  * @throws {Error} Throws an error if the subgroupId or brandIds parameters are missing
177
183
  * @returns {Promise<Object>} The response from the server
@@ -187,7 +193,7 @@ export class Brands {
187
193
  * @async
188
194
  * @roles api, admin, developer, billing, user
189
195
  * @param {Object} params - The parameters for creating external vetting
190
- * @param {string} params.brandId - The ID of the brand to create external vetting for
196
+ * @param {BrandLookupId} params.brandId - Brand lookup id (carrier Brand ID, Mongo `_id`, or internal reference).
191
197
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
192
198
  * @throws {Error} Throws an error if the brandId parameter is missing
193
199
  * @returns {Promise<Object>} The response from the server
@@ -207,7 +213,7 @@ export class Brands {
207
213
  * @async
208
214
  * @roles api, admin, developer, billing, user
209
215
  * @param {Object} params - The parameters for importing external vetting
210
- * @param {string} params.brandId - The ID of the brand to import external vetting for
216
+ * @param {BrandLookupId} params.brandId - Brand lookup id (carrier Brand ID, Mongo `_id`, or internal reference).
211
217
  * @param {string} params.vettingProviderId - The external vetting provider (AEGIS, WMC, CV)
212
218
  * @param {string} params.vettingId - The provider-issued vetting / transaction ID to import
213
219
  * @param {string} [params.vettingToken] - The provider-issued vetting token (required by some providers, e.g. AEGIS)
@@ -226,7 +232,7 @@ export class Brands {
226
232
  * @async
227
233
  * @roles api, admin, developer, billing, user
228
234
  * @param {Object} params - The parameters for updating the brand (see UpdateBrandData typedef for details)
229
- * @param {string} params.brandId - The ID of the brand to update
235
+ * @param {BrandLookupId} params.brandId - Brand lookup id (carrier Brand ID, Mongo `_id`, or internal reference).
230
236
  * @param {UpdateBrandData} params.brandData - The data for the brand to be updated
231
237
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
232
238
  * @throws {Error} Throws an error if the brandId parameter is missing
@@ -243,7 +249,7 @@ export class Brands {
243
249
  * @async
244
250
  * @roles api, admin, developer, billing, user
245
251
  * @param {Object} params - The parameters for reverting the brand
246
- * @param {string} params.brandId - The ID of the brand to revert
252
+ * @param {BrandLookupId} params.brandId - Brand lookup id (carrier Brand ID, Mongo `_id`, or internal reference).
247
253
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
248
254
  * @throws {Error} Throws an error if the brandId parameter is missing
249
255
  * @returns {Promise<Object>} The response from the server
@@ -259,7 +265,7 @@ export class Brands {
259
265
  * @async
260
266
  * @roles api, admin, developer, billing, user
261
267
  * @param {Object} params - The parameters for deleting the brand
262
- * @param {string} params.brandId - The ID of the brand to delete
268
+ * @param {BrandLookupId} params.brandId - Brand lookup id (carrier Brand ID, Mongo `_id`, or internal reference).
263
269
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
264
270
  * @throws {Error} Throws an error if the brandId parameter is missing
265
271
  * @returns {Promise<Object>} The response from the server
@@ -275,7 +281,7 @@ export class Brands {
275
281
  * @async
276
282
  * @roles api, admin, developer, billing, user
277
283
  * @param {Object} params - The parameters for getting the appeal history
278
- * @param {string} params.brandId - The ID of the brand to get appeal history for
284
+ * @param {BrandLookupId} params.brandId - Brand lookup id (carrier Brand ID, Mongo `_id`, or internal reference).
279
285
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
280
286
  * @throws {Error} Throws an error if the brandId parameter is missing
281
287
  * @returns {Promise<Array>} Array of BrandAppeal objects
@@ -291,7 +297,7 @@ export class Brands {
291
297
  * @async
292
298
  * @roles api, admin, developer, billing, user
293
299
  * @param {Object} params - The parameters for submitting the appeal
294
- * @param {string} params.brandId - The ID of the brand to appeal
300
+ * @param {BrandLookupId} params.brandId - Brand lookup id (carrier Brand ID, Mongo `_id`, or internal reference).
295
301
  * @param {Array<string>} params.appealCategories - Array of appeal categories (VERIFY_TAX_ID, VERIFY_NON_PROFIT, VERIFY_GOVERNMENT)
296
302
  * @param {string} params.explanation - Required explanation justifying the appeal
297
303
  * @param {File|Blob} params.file - The supporting document file
@@ -64,12 +64,12 @@
64
64
  * @property {string} [privacyPolicyLink] - A URL linking to the privacy policy for the campaign (optional, must be at most 2048 characters if provided)
65
65
  * @property {string} [termsAndConditionsLink] - A URL linking to the terms and conditions for the campaign (optional, must be at most 2048 characters if provided)
66
66
  * @property {string} [embeddedLinkSample] - A sample of the embedded link used in the campaign (optional, must be at most 255 characters if provided)
67
- * @property {Object} [tollFree] - Toll-Free editable fields, used when updating a Toll-Free campaign. Mirrors the CreateTollFreeCampaignData `tollFree` object with every field optional (useCase, messageVolume, programSummary (500), exampleMessage, customerCareEmail, optInImageURLs, optIns, multiNumberReason (≤500)). Phone numbers cannot be changed via update — Toll-Free numbers are locked to their campaign.
67
+ * @property {Object} [tollFree] - Toll-Free editable fields, used when updating a Toll-Free campaign. Mirrors the CreateTollFreeCampaignData `tollFree` object with every field optional (useCase, messageVolume, programSummary (40-500), exampleMessage, customerCareEmail, optInImageURLs, optIns, multiNumberReason (≤500)). Phone numbers cannot be changed via update — Toll-Free numbers are locked to their campaign.
68
68
  */
69
69
 
70
70
  /**
71
71
  * @typedef {Object} TollFreeOptIn
72
- * @property {string} [callToAction] - The opt-in call-to-action text for this channel (optional, at most 2048 characters)
72
+ * @property {string} [callToAction] - The opt-in call-to-action text for this channel (optional, 20-1024 characters when provided)
73
73
  * @property {string} [url] - The opt-in web URL (web channel only, optional, at most 2048 characters)
74
74
  * @property {Array<string>} [keywords] - The opt-in keywords (keyword channel only, optional)
75
75
  */
@@ -78,7 +78,7 @@
78
78
  * @typedef {Object} TollFreeCampaignDetails
79
79
  * @property {string} useCase - The Toll-Free use case (required, e.g. TWO_FA, GENERAL_MARKETING, HEALTHCARE, MIXED — one of the Toll-Free use-case values)
80
80
  * @property {string} messageVolume - The estimated monthly message volume tier (required, one of TEN, HUNDRED, THOUSAND, TEN_THOUSAND, HUNDRED_THOUSAND, TWO_HUNDRED_FIFTY_THOUSAND, FIVE_HUNDRED_THOUSAND, SEVEN_HUNDRED_FIFTY_THOUSAND, ONE_MILLION, FIVE_MILLION, TEN_MILLION_PLUS)
81
- * @property {string} programSummary - A summary of the messaging program (required, at most 500 characters)
81
+ * @property {string} programSummary - A summary of the messaging program (required, 40-500 characters)
82
82
  * @property {string} exampleMessage - An example message (required, at most 4096 characters; stored verbatim, no STOP/HELP appended by the server)
83
83
  * @property {string} customerCareEmail - A customer-care contact email (required, valid email)
84
84
  * @property {Array<string>} optInImageURLs - URLs to opt-in proof images (required, at least one, each at most 2048 characters)
@@ -102,8 +102,9 @@
102
102
  */
103
103
 
104
104
  export class Campaigns {
105
- constructor(client, enableAdmin) {
105
+ constructor(client, multipartClient, enableAdmin) {
106
106
  this.client = client;
107
+ this.multipartClient = multipartClient;
107
108
  this.enableAdmin = enableAdmin;
108
109
 
109
110
  if (enableAdmin) {
@@ -178,6 +179,22 @@ export class Campaigns {
178
179
  return this.client(`/campaign${queryString}`, { method: "GET", ...options });
179
180
  }
180
181
 
182
+ /**
183
+ * Get aggregated campaign health (7-day and 30-day windows) for a campaign.
184
+ * @async
185
+ * @roles api, admin, developer, billing, user
186
+ * @param {Object} params - Parameters for reading campaign health
187
+ * @param {string} params.campaignId - Campaign identifier
188
+ * @param {boolean} [params.includeNumbers=false] - When true, include per-number health entries
189
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional request options
190
+ * @returns {Promise<Object>} A promise that resolves to `{ campaignId, sevenDay, thirtyDay, numbers? }`
191
+ */
192
+ async getCampaignHealth({ campaignId, includeNumbers = false, options = {} }) {
193
+ this.client._require({ campaignId });
194
+ const queryString = this.client._getQueryString({ campaignId, includeNumbers });
195
+ return this.client(`/campaign/health${queryString}`, { method: "GET", ...options });
196
+ }
197
+
181
198
  /**
182
199
  * Create a new campaign
183
200
  * @async
@@ -208,6 +225,40 @@ export class Campaigns {
208
225
  return this.client(`/campaign/toll-free`, { method: "POST", body: campaignData, ...options });
209
226
  }
210
227
 
228
+ /**
229
+ * Upload an opt-in proof image to be hosted on-platform, returning a publicly-fetchable URL suitable for a
230
+ * Toll-Free campaign's optInImageURLs
231
+ * @async
232
+ * @roles api, admin, developer, user
233
+ * @param {Object} params - The parameters for uploading the opt-in image
234
+ * @param {Buffer|Blob|File} params.file - The image file to upload, provided as a Buffer/Blob/File
235
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
236
+ * @throws {Error} Throws an error if the file parameter is missing
237
+ * @returns {Promise<Object>} The response from the server containing the hosted image's id and URL
238
+ */
239
+ async uploadOptInImage({ file, options = {} }) {
240
+ this.client._require({ file });
241
+ const formData = new FormData();
242
+ formData.append("file", file);
243
+ return this.multipartClient(`/campaign/opt-in-image`, { method: "POST", body: formData, ...options });
244
+ }
245
+
246
+ /**
247
+ * Auto-capture an opt-in proof image from a brand's generated landing page and host it on-platform,
248
+ * returning a publicly-fetchable URL suitable for a Toll-Free campaign's optInImageURLs
249
+ * @async
250
+ * @roles api, admin, developer, user
251
+ * @param {Object} params - The parameters for capturing the opt-in image
252
+ * @param {string} params.brandId - The ID of the brand whose generated landing page should be captured
253
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
254
+ * @throws {Error} Throws an error if the brandId parameter is missing
255
+ * @returns {Promise<Object>} The response from the server containing the hosted image's id and URL
256
+ */
257
+ async captureOptInImageFromLanding({ brandId, options = {} }) {
258
+ this.client._require({ brandId });
259
+ return this.client(`/campaign/opt-in-image/from-landing`, { method: "POST", body: { brandId }, ...options });
260
+ }
261
+
211
262
  /**
212
263
  * Update an existing campaign
213
264
  * @async
@@ -18,6 +18,8 @@ export class Messages {
18
18
  * @param {string} [params.status] - Filter messages by their status (ENQUEUED, DEQUEUED, SENT, FAILED, DELIVERED)
19
19
  * @param {string} [params.direction] - Filter messages by their direction (INBOUND, OUTBOUND)
20
20
  * @param {string|string[]} [params.messageType] - Filter messages by their type. Accepts a single value or an array (e.g. ["SMS", "MMS"]). Allowed values: SMS, MMS, RCS, WHATSAPP, VIBER, P2P. When omitted, defaults to all non-P2P types.
21
+ * @param {string|string[]} [params.channel] - Filter messages by channel. Accepts a single value or an array. Allowed values: tenDLC, tollFree, p2p. Each message records its channel when it is saved, and this filters on that stored value; older messages from before this feature have no channel and count as tenDLC. Ignored when matchAny is true (matchAny takes precedence).
22
+ * @param {boolean} [params.matchAny] - When true, the provided campaignId/brandId/phoneNumber filters are OR'd (a message matches ANY of them) instead of the default most-specific-single behavior. subgroupId stays an AND scope. Opt-in/additive.
21
23
  * @param {string} [params.carrier] - Filter messages by the carrier used for sending
22
24
  * @param {string} [params.senderPhoneNumber] - Filter messages by the sender's phone number
23
25
  * @param {string} [params.recipientPhoneNumber] - Filter messages by the recipient's phone number
@@ -42,6 +44,8 @@ export class Messages {
42
44
  status,
43
45
  direction,
44
46
  messageType,
47
+ channel,
48
+ matchAny,
45
49
  carrier,
46
50
  startDate,
47
51
  endDate,
@@ -51,7 +55,7 @@ export class Messages {
51
55
  limit,
52
56
  options = {},
53
57
  }) {
54
- const filters = { id, campaignId, brandId, subgroupId, groupId, phoneNumber, senderPhoneNumber, recipientPhoneNumber, status, direction, messageType, carrier, startDate, endDate, sortField, sortOrder, page, limit };
58
+ const filters = { id, campaignId, brandId, subgroupId, groupId, phoneNumber, senderPhoneNumber, recipientPhoneNumber, status, direction, messageType, channel, matchAny, carrier, startDate, endDate, sortField, sortOrder, page, limit };
55
59
  const queryString = this.client._getQueryString(filters);
56
60
  return this.client(`/message${queryString}`, { method: "GET", ...options });
57
61
  }
@@ -89,11 +93,13 @@ export class Messages {
89
93
  * @param {string} [params.carrier] - Filter analytics by the carrier used for sending
90
94
  * @param {string} [params.startDate] - ISO-8601 date or timestamp; normalized to start-of-UTC-day (inclusive)
91
95
  * @param {string} [params.endDate] - ISO-8601 date or timestamp; normalized to end-of-UTC-day (inclusive). Hourly resolution is not supported
96
+ * @param {boolean} [params.matchAny] - When true, the provided campaignId/brandId/phoneNumber filters are OR'd (match ANY) instead of the default most-specific-single behavior. subgroupId stays an AND scope. Opt-in/additive.
97
+ * @param {string|string[]} [params.channel] - Filter analytics by channel (tenDLC, tollFree, p2p). Filters on the stored channel column; a tenDLC selection also includes older messages that have no channel, and p2p is a real channel here (matched by carrier). Accepts a single value or an array. Ignored when matchAny is true (matchAny takes precedence).
92
98
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
93
99
  * @returns {Promise<Object>} - A promise that resolves to the analytics data
94
100
  */
95
- async getAnalytics({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, options = {} }) {
96
- const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate };
101
+ async getAnalytics({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, channel, matchAny, options = {} }) {
102
+ const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, channel, matchAny };
97
103
  const queryString = this.client._getQueryString(filters);
98
104
  return this.client(`/message/analytics${queryString}`, { method: "GET", ...options });
99
105
  }
@@ -111,11 +117,12 @@ export class Messages {
111
117
  * @param {string} [params.carrier] - Filter analytics by the carrier used for sending
112
118
  * @param {string} [params.startDate] - ISO-8601 date or timestamp; normalized to start-of-UTC-day (inclusive)
113
119
  * @param {string} [params.endDate] - ISO-8601 date or timestamp; normalized to end-of-UTC-day (inclusive). Hourly resolution is not supported
120
+ * @param {string|string[]} [params.channel] - Filter analytics by channel (tenDLC, tollFree, p2p). Filters on the stored channel column; a tenDLC selection also includes older messages that have no channel, and p2p is a real channel here. Accepts a single value or an array.
114
121
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
115
122
  * @returns {Promise<Array>} - A promise that resolves to an array of analytics snapshot records
116
123
  */
117
- async getAnalyticsDetail({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, options = {} }) {
118
- const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate };
124
+ async getAnalyticsDetail({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, channel, options = {} }) {
125
+ const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, channel };
119
126
  const queryString = this.client._getQueryString(filters);
120
127
  return this.client(`/message/analytics/detail${queryString}`, { method: "GET", ...options });
121
128
  }
@@ -152,7 +159,7 @@ export class Messages {
152
159
  * @param {string} [params.endDate]
153
160
  * @param {number} [params.page=1]
154
161
  * @param {number} [params.limit=50] - max 50 per page
155
- * @param {"tenDLC"|"p2p"|"both"} [params.channel="both"] - Scope the ORDER BY + row inclusion. "tenDLC" excludes rows with no SMS/MMS activity; "p2p" excludes rows with no P2P activity; "both" returns rows with any activity.
162
+ * @param {("tenDLC"|"tollFree"|"p2p"|"both")|Array<"tenDLC"|"tollFree"|"p2p">} [params.channel="both"] - Filter and rank rows by the stored channel column. "both" (default) means all activity. tenDLC/tollFree/p2p (single value or array) limit to the selected channel(s); toll-free is kept separate from 10DLC using the stored channel column.
156
163
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options]
157
164
  * @returns {Promise<Object>} - { rows, totalCount, page, limit }. Each row carries sms/mms/p2p metric columns plus `smsOptOuts` and `mmsOptOuts` from the DNC analytics MV (P2P has no opt-outs).
158
165
  */
@@ -178,7 +185,7 @@ export class Messages {
178
185
  * @param {string} [params.endDate]
179
186
  * @param {number} [params.page=1]
180
187
  * @param {number} [params.limit=50] - max 50 per page
181
- * @param {"tenDLC"|"p2p"|"both"} [params.channel="both"] - Scope the ORDER BY + totalCount. "tenDLC" excludes rows with no SMS/MMS errors; "p2p" excludes rows with no P2P errors; "both" returns rows with any error.
188
+ * @param {("tenDLC"|"tollFree"|"p2p"|"both")|Array<"tenDLC"|"tollFree"|"p2p">} [params.channel="both"] - Filter and rank rows by the stored channel column. "both" (default) means every code. tenDLC/tollFree/p2p (single value or array) limit to the selected channel(s); when one channel is selected, totalErrors reflects only that channel.
182
189
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options]
183
190
  * @returns {Promise<Object>} - { rows, totalCount, totalErrors: { sms, mms, p2p, all }, page, limit }
184
191
  */
@@ -201,11 +208,12 @@ export class Messages {
201
208
  * @param {string} [params.carrier] - Filter by the carrier
202
209
  * @param {string} [params.startDate] - ISO-8601 date or timestamp; normalized to start-of-UTC-day (inclusive)
203
210
  * @param {string} [params.endDate] - ISO-8601 date or timestamp; normalized to end-of-UTC-day (inclusive). Hourly resolution is not supported
211
+ * @param {string|string[]} [params.channel] - Filter by channel (tenDLC, tollFree). Opt-outs are A2P-only, so p2p applies no filter. Filters on the stored channel column; a tenDLC selection also includes older opt-outs that have no channel.
204
212
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
205
213
  * @returns {Promise<Object>} - A promise that resolves to the DNC analytics data (totals, byDate, byPhoneNumber, byCarrier)
206
214
  */
207
- async getDncAnalytics({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, options = {} }) {
208
- const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate };
215
+ async getDncAnalytics({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, channel, options = {} }) {
216
+ const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, channel };
209
217
  const queryString = this.client._getQueryString(filters);
210
218
  return this.client(`/message/dnc/analytics${queryString}`, { method: "GET", ...options });
211
219
  }
@@ -227,11 +235,12 @@ export class Messages {
227
235
  * @param {number} [params.limit] - Number of records per page
228
236
  * @param {string} [params.sortField] - Field to sort by
229
237
  * @param {string} [params.sortOrder] - Sort direction (asc, desc)
238
+ * @param {string|string[]} [params.channel] - Filter by channel (tenDLC, tollFree). Opt-outs are A2P-only, so p2p applies no filter. Filters on the stored channel column; a tenDLC selection also includes older opt-outs that have no channel.
230
239
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
231
240
  * @returns {Promise<Object>} - A promise that resolves to the paginated DNC records
232
241
  */
233
- async getDncRecords({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, page, limit, sortField, sortOrder, options = {} }) {
234
- const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, page, limit, sortField, sortOrder };
242
+ async getDncRecords({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, page, limit, sortField, sortOrder, channel, options = {} }) {
243
+ const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, page, limit, sortField, sortOrder, channel };
235
244
  const queryString = this.client._getQueryString(filters);
236
245
  return this.client(`/message/dnc${queryString}`, { method: "GET", ...options });
237
246
  }
@@ -267,13 +276,17 @@ export class Messages {
267
276
  * @param {string[]} params.recipientPhoneNumbers - The phone number(s) to send the message to
268
277
  * @param {string} params.messageBody - The body of the P2P message
269
278
  * @param {string} [params.statusCallbackUrl] - The URL to receive status callbacks
279
+ * @param {boolean} [params.useSignalHouseShortlinks] - When false, SignalHouse applies no link-shortening
280
+ * or text-spin and your pre-spun links/content are sent verbatim (bring-your-own spinner). Defaults to
281
+ * true server-side (the SignalHouse shortlink system, which mints unique per-recipient links).
270
282
  * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
271
283
  * @returns {Promise<Object>} - A promise that resolves to the response data from the server
272
284
  */
273
- async sendP2P({ recipientPhoneNumbers, messageBody, statusCallbackUrl, options = {} }) {
285
+ async sendP2P({ recipientPhoneNumbers, messageBody, statusCallbackUrl, useSignalHouseShortlinks, options = {} }) {
274
286
  this.client._require({ recipientPhoneNumbers, messageBody });
275
287
  const body = { recipientPhoneNumber: recipientPhoneNumbers, messageBody };
276
288
  if (statusCallbackUrl) body.statusCallbackUrl = statusCallbackUrl;
289
+ if (typeof useSignalHouseShortlinks === "boolean") body.useSignalHouseShortlinks = useSignalHouseShortlinks;
277
290
  return this.client(`/message/p2p`, {
278
291
  method: "POST",
279
292
  body,
@@ -68,6 +68,22 @@ export class Numbers {
68
68
  return this.client(`/number${queryString}`, { method: "GET", ...options });
69
69
  }
70
70
 
71
+ /**
72
+ * Get the portal-parity health score (1–10) for an owned phone number over 7-day and 30-day windows
73
+ * @async
74
+ * @roles api, admin, developer, billing, user
75
+ * @param {Object} params - The parameters for reading number health
76
+ * @param {string} params.phoneNumber - Owned phone number to score (11 digits, no + prefix)
77
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
78
+ * @throws {Error} Throws an error if the phoneNumber parameter is missing
79
+ * @returns {Promise<Object>} A promise that resolves to `{ phoneNumber, groupId, sevenDay, thirtyDay }`
80
+ */
81
+ async getNumberHealth({ phoneNumber, options = {} }) {
82
+ this.client._require({ phoneNumber });
83
+ const queryString = this.client._getQueryString({ phoneNumber });
84
+ return this.client(`/number/health${queryString}`, { method: "GET", ...options });
85
+ }
86
+
71
87
  /**
72
88
  * Get a list of available phone numbers for purchase with optional filters
73
89
  * @async
@@ -0,0 +1,80 @@
1
+ export class Tickets {
2
+ constructor(client, enableAdmin) {
3
+ this.client = client;
4
+ this.enableAdmin = enableAdmin;
5
+
6
+ // Hidden Admin namespace INSIDE the domain (staff-only customer ticket → Jira)
7
+ if (enableAdmin) {
8
+ this.admin = {
9
+ /**
10
+ * Load Jira form metadata (issue types, priorities, active sprint, field IDs). Staff-only.
11
+ * @async
12
+ * @roles signalhouse
13
+ * @param {Object} [params] - Optional parameters
14
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
15
+ * @returns {Promise<Object>} - Jira form metadata
16
+ */
17
+ getJiraMetadata: async ({ options = {} } = {}) => {
18
+ return this.client(`/admin/ticket/jira/metadata`, { method: "GET", ...options });
19
+ },
20
+
21
+ /**
22
+ * Search open SHGHL epics for the parent picker. Staff-only.
23
+ * @async
24
+ * @roles signalhouse
25
+ * @param {Object} [params]
26
+ * @param {string} [params.query] - Optional epic summary/key filter
27
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
28
+ * @returns {Promise<Object>} - `{ epics: Array<{ id, key, summary }> }`
29
+ */
30
+ searchJiraEpics: async ({ query, options = {} } = {}) => {
31
+ const queryString = this.client._getQueryString({ query });
32
+ return this.client(`/admin/ticket/jira/epics${queryString}`, { method: "GET", ...options });
33
+ },
34
+
35
+ /**
36
+ * Search assignable Jira users for the assignee picker. Staff-only.
37
+ * @async
38
+ * @roles signalhouse
39
+ * @param {Object} [params]
40
+ * @param {string} [params.query] - Partial name or email
41
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
42
+ * @returns {Promise<Object>} - `{ users: Array<{ accountId, displayName, emailAddress }> }`
43
+ */
44
+ searchJiraAssignees: async ({ query, options = {} } = {}) => {
45
+ const queryString = this.client._getQueryString({ query });
46
+ return this.client(`/admin/ticket/jira/assignees${queryString}`, { method: "GET", ...options });
47
+ },
48
+
49
+ /**
50
+ * Suggest Jira labels matching a query. Staff-only.
51
+ * @async
52
+ * @roles signalhouse
53
+ * @param {Object} [params]
54
+ * @param {string} [params.query] - Partial label text
55
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
56
+ * @returns {Promise<Object>} - `{ labels: string[] }`
57
+ */
58
+ searchJiraLabels: async ({ query, options = {} } = {}) => {
59
+ const queryString = this.client._getQueryString({ query });
60
+ return this.client(`/admin/ticket/jira/labels${queryString}`, { method: "GET", ...options });
61
+ },
62
+
63
+ /**
64
+ * Create a Jira ticket from the admin customer ticket form. Staff-only.
65
+ * @async
66
+ * @roles signalhouse
67
+ * @param {Object} params
68
+ * @param {Object} params.data - Create payload (groupId, issueTypeId, priorityId, summary required)
69
+ * @param {import('../SignalHouseSDK').RequestOptions} [params.options] - Additional options for the request
70
+ * @throws {Error} Throws an error if the data parameter is missing
71
+ * @returns {Promise<Object>} - Created ticket summary (key, browseUrl, reporter, etc.)
72
+ */
73
+ createJiraTicket: async ({ data, options = {} }) => {
74
+ this.client._require({ data });
75
+ return this.client(`/admin/ticket/jira`, { method: "POST", body: data, ...options });
76
+ },
77
+ };
78
+ }
79
+ }
80
+ }