@signalhousellc/sdk 1.0.68 → 1.1.0

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.
@@ -140,11 +140,64 @@ export class Brands {
140
140
  * @param {number} [params.limit] - The number of items per page
141
141
  * @param {string} [params.status] - The status of the brand to filter by (PENDING_CREATION, PENDING_APPROVAL, UNVERIFIED, VERIFIED, VETTED_VERIFIED, PENDING_DELETE, DELETED)
142
142
  * @param {string} [params.registrationType] - Filter by registration type ("TEN_DLC", "TOLL_FREE", or "SHORT_CODE")
143
+ * @param {string} [params.search] - Staff-only (no id/subgroupId/groupId): case-insensitive substring over brandId, names, EIN, email, group, subgroup and reference ID
144
+ * @param {string} [params.sortBy] - Staff-only: createdAt, brandId, displayName, groupId, subgroupId, status, entityType or country
145
+ * @param {"asc"|"desc"} [params.sortOrder] - Staff-only: sort direction (default asc)
146
+ * @param {string} [params.entityType] - Staff-only: exact entity type filter
147
+ * @param {string} [params.ein] - Staff-only: EIN substring filter
148
+ * @param {string} [params.email] - Staff-only: support email substring filter
149
+ * @param {string} [params.referenceId] - Staff-only: reference ID substring filter
150
+ * @param {string|Array<string>} [params.groupIds] - Staff-only: restrict to these group IDs (sent comma-separated)
151
+ * @param {string} [params.createdFrom] - Staff-only: inclusive createdAt lower bound (ISO date)
152
+ * @param {string} [params.createdTo] - Staff-only: inclusive createdAt upper bound (ISO date)
153
+ * @param {boolean} [params.excludeDeleted] - Staff-only: hide DELETED brands when no status is given
154
+ * @param {boolean} [params.includeTotal] - Staff-only: with page and limit, return `{ data, total, page, limit, totalPages }` instead of the array
143
155
  * @param {RequestOptions} [params.options] - Additional options for the request
144
- * @returns {Promise<SdkResponse<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.
156
+ * @returns {Promise<SdkResponse<Array<{ _id: string, brandId: string|null, status: string, registrationType: string, [key: string]: any }>|{ data: Array<Object>, total: number, page: number, limit: number, totalPages: number }>>} 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. The staff-only list (no id/subgroupId/groupId) returns the `{ data, total, page, limit, totalPages }` envelope only when includeTotal is sent with page and limit.
145
157
  */
146
- async getBrands({ id, subgroupId, groupId, page, limit, status, registrationType, options = {} }) {
147
- const filters = { id, subgroupId, groupId, page, limit, status, registrationType };
158
+ async getBrands({
159
+ id,
160
+ subgroupId,
161
+ groupId,
162
+ page,
163
+ limit,
164
+ status,
165
+ registrationType,
166
+ search,
167
+ sortBy,
168
+ sortOrder,
169
+ entityType,
170
+ ein,
171
+ email,
172
+ referenceId,
173
+ groupIds,
174
+ createdFrom,
175
+ createdTo,
176
+ excludeDeleted,
177
+ includeTotal,
178
+ options = {},
179
+ }) {
180
+ const filters = {
181
+ id,
182
+ subgroupId,
183
+ groupId,
184
+ page,
185
+ limit,
186
+ status,
187
+ registrationType,
188
+ search,
189
+ sortBy,
190
+ sortOrder,
191
+ entityType,
192
+ ein,
193
+ email,
194
+ referenceId,
195
+ groupIds: Array.isArray(groupIds) ? (groupIds.length ? groupIds.join(',') : undefined) : groupIds,
196
+ createdFrom,
197
+ createdTo,
198
+ excludeDeleted,
199
+ includeTotal,
200
+ };
148
201
  const queryString = this.client._getQueryString(filters);
149
202
  return this.client(`/brand${queryString}`, { method: 'GET', ...options });
150
203
  }
@@ -0,0 +1,168 @@
1
+ /** @typedef {import('../SignalHouseSDK.js').RequestOptions} RequestOptions */
2
+ /**
3
+ * @template T
4
+ * @typedef {import('../SignalHouseSDK.js').SdkResponse<T>} SdkResponse
5
+ */
6
+
7
+ /**
8
+ * Do Not Contact domain: the attested "Disable Automated Opt-Out" account setting. Signal House
9
+ * suppresses sends to recipients who opted out of the sending campaign by default; an account may
10
+ * disable that only by having an officer read and e-sign the Opt-Out Handling Attestation inside a
11
+ * Signal House app: the portal (a customer login signs for its own account) or one of our apps running
12
+ * as signalhouse_api (GHL, Shopify), which signs for the account it names on behalf of the customer user
13
+ * it authenticated. Every method therefore lives under the admin namespace (present only when the SDK is
14
+ * created with `enableAdmin: true`), and the API refuses the customer "api" (API key) role on the signing
15
+ * routes, so attestation can never be performed by a third-party integration.
16
+ */
17
+ export class Dnc {
18
+ constructor(client, enableAdmin) {
19
+ this.client = client;
20
+ this.enableAdmin = enableAdmin;
21
+
22
+ // Hidden Admin namespace INSIDE the domain
23
+ if (enableAdmin) {
24
+ this.admin = {
25
+ /**
26
+ * Get the current Opt-Out Handling Attestation text for the session's account with every placeholder
27
+ * filled (account values, the session's email and role, blanks in the signature block for what only
28
+ * signing supplies), plus the version and template hash a signature must echo back. The app must
29
+ * render this text; it never ships its own copy.
30
+ * @async
31
+ * @roles admin, developer, billing (portal logins); signalhouse_* with groupId
32
+ * @param {Object} [params] - Optional parameters
33
+ * @param {string} [params.groupId] - Group to render for (apps and staff; customers always get their active group)
34
+ * @param {RequestOptions} [params.options] - Additional options for the request
35
+ * @returns {Promise<SdkResponse<any>>} - `{ version, templateSha256, text, checkboxText, groupId, accountName, customerLegalName }`
36
+ */
37
+ getCurrentAttestation: async ({ groupId, options = {} } = {}) => {
38
+ const queryString = this.client._getQueryString({ groupId });
39
+ return this.client(`/dnc/attestation/current${queryString}`, { method: "GET", ...options });
40
+ },
41
+
42
+ /**
43
+ * Sign the attestation and disable automated opt-out suppression for the account and every subgroup,
44
+ * effective within about a minute on every API instance. Two callers: a portal login signs for its own
45
+ * account and the signer identity is taken from the session; a Signal House app running as
46
+ * signalhouse_api (GHL, Shopify) signs for the `groupId` it names and supplies the identity of the
47
+ * customer user it authenticated (`signerEmail`, optional `signerUserId`, `signedVia`, and the end
48
+ * user's `signerIpAddress` / `signerUserAgent`, which otherwise default to the app server's). Resolves
49
+ * 201 when this call created the record and 200 with the existing record on a repeat or concurrent
50
+ * call. A stale version or hash is refused with 409 and `details.code === "ATTESTATION_VERSION_MISMATCH"`;
51
+ * an unchecked box or blank field with 400. Human staff roles and customer API-key sessions are refused.
52
+ * @async
53
+ * @roles admin, developer, billing (portal logins); signalhouse_api (apps, with groupId)
54
+ * @param {Object} params
55
+ * @param {string} params.version - The version returned by getCurrentAttestation
56
+ * @param {string} params.templateSha256 - The template hash returned by getCurrentAttestation
57
+ * @param {boolean} params.checkboxAcknowledged - Must be true
58
+ * @param {boolean} params.scrolledToEnd - Must be true
59
+ * @param {string} params.customerLegalName - Company legal name
60
+ * @param {string} params.signerName - Signer's typed full legal name (the electronic signature)
61
+ * @param {string} params.signerTitle - Signer's title
62
+ * @param {string} [params.groupId] - App callers: the account being attested
63
+ * @param {string} [params.signerEmail] - App callers (required): the signer's email as authenticated by the app
64
+ * @param {string} [params.signerUserId] - App callers: the app's id for the signer
65
+ * @param {string} [params.signedVia] - App callers: the app name, e.g. "ghl" or "shopify"
66
+ * @param {string} [params.signerIpAddress] - App callers: the end user's IP address
67
+ * @param {string} [params.signerUserAgent] - App callers: the end user's user agent
68
+ * @param {RequestOptions} [params.options] - Additional options for the request
69
+ * @throws {Error} Throws an error if a required parameter is missing
70
+ * @returns {Promise<SdkResponse<any>>} - `{ attestation, created }`
71
+ */
72
+ signAttestation: async ({ version, templateSha256, checkboxAcknowledged, scrolledToEnd, customerLegalName, signerName, signerTitle, groupId, signerEmail, signerUserId, signedVia, signerIpAddress, signerUserAgent, options = {} }) => {
73
+ this.client._require({ version, templateSha256, customerLegalName, signerName, signerTitle });
74
+ const appFields = Object.fromEntries(Object.entries({ groupId, signerEmail, signerUserId, signedVia, signerIpAddress, signerUserAgent }).filter(([, value]) => value !== undefined));
75
+ return this.client(`/dnc/attestation`, {
76
+ method: "POST",
77
+ body: { version, templateSha256, checkboxAcknowledged, scrolledToEnd, customerLegalName, signerName, signerTitle, ...appFields },
78
+ ...options,
79
+ });
80
+ },
81
+
82
+ /**
83
+ * Revoke the active attestation and re-enable automated opt-out suppression, effective within about a
84
+ * minute: a portal login for its own account, or an app (signalhouse_api) for the `groupId` it names.
85
+ * The record is retained as "revoked". 404 when nothing is active.
86
+ * @async
87
+ * @roles admin, developer, billing (portal logins); signalhouse_api (apps, with groupId)
88
+ * @param {Object} [params] - Optional parameters
89
+ * @param {string} [params.groupId] - App callers: the account
90
+ * @param {RequestOptions} [params.options] - Additional options for the request
91
+ * @returns {Promise<SdkResponse<any>>} - `{ attestation }`
92
+ */
93
+ revokeAttestation: async ({ groupId, options = {} } = {}) => {
94
+ return this.client(`/dnc/attestation/revoke`, { method: "POST", ...(groupId ? { body: { groupId } } : {}), ...options });
95
+ },
96
+
97
+ /**
98
+ * Read an account's attestation state: whether automated opt-out is disabled, the active record
99
+ * (full stored text included), the full history, and whether the active record predates the
100
+ * current template and must be re-signed by `resignDeadline`.
101
+ * @async
102
+ * @roles admin, developer, billing (portal logins); signalhouse_* with groupId
103
+ * @param {Object} [params] - Optional parameters
104
+ * @param {string} [params.groupId] - Group to read (apps and staff; customers always get their active group)
105
+ * @param {RequestOptions} [params.options] - Additional options for the request
106
+ * @returns {Promise<SdkResponse<any>>} - `{ groupId, automatedOptOutDisabled, currentVersion, currentTemplateSha256, requiresResign, resignDeadline, active, history }`
107
+ */
108
+ getAttestation: async ({ groupId, options = {} } = {}) => {
109
+ const queryString = this.client._getQueryString({ groupId });
110
+ return this.client(`/dnc/attestation${queryString}`, { method: "GET", ...options });
111
+ },
112
+
113
+ /**
114
+ * List opt-out attestations across every account, newest first, with each group's trailing
115
+ * would-have-suppressed counts (7 and 30 days, recorded while attested) and 7-day opt-out count.
116
+ * The full attestation text is omitted from list rows. Staff-only.
117
+ * @async
118
+ * @roles signalhouse
119
+ * @param {Object} [params] - Optional parameters
120
+ * @param {("active"|"revoked"|"superseded")} [params.status] - Filter by status
121
+ * @param {string} [params.groupId] - Filter by group
122
+ * @param {number} [params.page] - Page number (default 1)
123
+ * @param {number} [params.limit] - Rows per page (default 50, max 500)
124
+ * @param {RequestOptions} [params.options] - Additional options for the request
125
+ * @returns {Promise<SdkResponse<any>>} - `{ rows, totalCount, page, limit }`
126
+ */
127
+ listAttestations: async ({ status, groupId, page, limit, options = {} } = {}) => {
128
+ const queryString = this.client._getQueryString({ status, groupId, page, limit });
129
+ return this.client(`/dnc/attestations${queryString}`, { method: "GET", ...options });
130
+ },
131
+
132
+ /**
133
+ * Read one attestation with its stored text, hashes, signer identity, IP and user agent, plus
134
+ * the group's full attestation history. Staff-only.
135
+ * @async
136
+ * @roles signalhouse
137
+ * @param {Object} params
138
+ * @param {string} params.id - The attestation id
139
+ * @param {RequestOptions} [params.options] - Additional options for the request
140
+ * @throws {Error} Throws an error if the id parameter is missing
141
+ * @returns {Promise<SdkResponse<any>>} - `{ attestation, history }`
142
+ */
143
+ getAttestationById: async ({ id, options = {} }) => {
144
+ this.client._require({ id });
145
+ return this.client(`/dnc/attestations/${encodeURIComponent(id)}`, { method: "GET", ...options });
146
+ },
147
+
148
+ /**
149
+ * Revoke an active attestation with a reason and re-enable automated opt-out for the account.
150
+ * Emails the signer and account owner. There is no staff path that creates an attestation. Staff-only.
151
+ * @async
152
+ * @roles signalhouse
153
+ * @param {Object} params
154
+ * @param {string} params.id - The attestation id
155
+ * @param {("carrier_complaint"|"regulator_inquiry"|"legal_request"|"excessive_opt_out_rate"|"customer_request"|"other")} params.reasonCode - Why it is being revoked
156
+ * @param {string} params.reason - Free-text reason shown to the customer
157
+ * @param {RequestOptions} [params.options] - Additional options for the request
158
+ * @throws {Error} Throws an error if a required parameter is missing
159
+ * @returns {Promise<SdkResponse<any>>} - `{ attestation }` (status "revoked", revokedByType "signalhouse_admin")
160
+ */
161
+ revokeAttestationById: async ({ id, reasonCode, reason, options = {} }) => {
162
+ this.client._require({ id, reasonCode, reason });
163
+ return this.client(`/dnc/attestations/${encodeURIComponent(id)}/revoke`, { method: "POST", body: { reasonCode, reason }, ...options });
164
+ },
165
+ };
166
+ }
167
+ }
168
+ }
@@ -4,6 +4,17 @@
4
4
  * @typedef {import('../SignalHouseSDK.js').SdkResponse<T>} SdkResponse
5
5
  */
6
6
 
7
+ /**
8
+ * Serialise regionScopes for the query string: an array of branches becomes JSON, a string is passed through.
9
+ * @param {Object} filters - Query filters that may carry regionScopes
10
+ * @returns {Object} - The filters with regionScopes JSON-encoded when present
11
+ */
12
+ function withRegionScopes(filters) {
13
+ if (filters.regionScopes === undefined) return filters;
14
+ const regionScopes = typeof filters.regionScopes === "string" ? filters.regionScopes : JSON.stringify(filters.regionScopes);
15
+ return { ...filters, regionScopes };
16
+ }
17
+
7
18
  export class Messages {
8
19
  constructor(client, multipartClient, enableAdmin) {
9
20
  this.client = client;
@@ -12,9 +23,12 @@ export class Messages {
12
23
  }
13
24
 
14
25
  /**
15
- * Estimate Canadian SMS/MMS retail cost without sending or charging.
26
+ * Estimate regional SMS/MMS retail cost; no charge or send. A Canadian sender requires a Ready Canadian sender and
27
+ * Canadian or US recipients, and is unavailable unless Canada is enabled for the environment. A +44 (UK) sender
28
+ * estimates SMS to GB mobiles only and returns region "GB"; while UK sending is disabled for the environment a UK
29
+ * sender is refused with a 400.
16
30
  * @async
17
- * @param {Object} params - Sender, up to 100 recipients, messageBody and request options.
31
+ * @param {Object} params - Sender, up to 100 recipients (10-15 digits each), messageBody and request options.
18
32
  * @returns {Promise<SdkResponse<any>>} - Per-recipient rates and total in microdollars; unknown carriers use the upper fallback.
19
33
  */
20
34
  async estimateMessage({ senderPhoneNumber, recipientPhoneNumbers, messageBody, messageType = "SMS", options = {} }) {
@@ -31,13 +45,17 @@ export class Messages {
31
45
  * @param {string} [params.brandId] - Filter messages by the ID of the associated brand
32
46
  * @param {string} [params.subgroupId] - Filter messages by the ID of the associated subgroup
33
47
  * @param {string} [params.groupId] - Filter messages by the ID of the associated group
48
+ * @param {string|string[]} [params.registrationId] - Filter to messages attributed to these registrations. Cannot be combined with campaignId; each id must belong to the group. Accepts a single value or an array.
34
49
  * @param {string} [params.status] - Filter messages by their status (ENQUEUED, DEQUEUED, SENT, FAILED, DELIVERED)
35
50
  * @param {string} [params.direction] - Filter messages by their direction (INBOUND, OUTBOUND)
36
51
  * @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.
37
52
  * @param {string|string[]} [params.channel] - Filter messages by channel. Accepts a single value or an array. Allowed values: tenDLC, virtualLongCode, tollFree, shortCode, 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).
53
+ * @param {string|string[]} [params.region] - ISO-2 country filter: US, GB or CA (UK is accepted for GB); one value, an array, or a comma-separated string; omitted = every region. Accepted whether or not the environment serves hourly analytics.
54
+ * @param {Object[]|string} [params.regionScopes] - Array of OR-ed branches `{ region, channels, brandId?, campaignId?, phoneNumber? }` (channels among tenDLC, virtualLongCode, tollFree, shortCode, p2p); `[]` matches nothing. Sent as JSON unless already a string. Accepted whether or not the environment serves hourly analytics.
38
55
  * @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.
39
56
  * @param {string} [params.carrier] - Filter messages by the carrier used for sending
40
57
  * @param {string|string[]} [params.sentimentLabel] - Filter messages by sentiment bucket. Accepts a single value or an array (e.g. ["positive", "negative"]). Allowed values: positive, neutral, negative. Applied as the sentimentScore range the ±25 label threshold produces, so unscored messages match no bucket and outbound messages (never scored) are excluded.
58
+ * @param {string|string[]} [params.errorCode] - Filter FAILED messages by Signal House error code (single value or array). "OUT" is the campaign opt-out, displayed as RECIPIENT_OPTED_OUT. Carrier codes are not filterable here; they live inside successOrFailureReason.
41
59
  * @param {string|string[]} [params.phoneNumber] - Filter messages by a business number on either side of the message. Accepts a single value or an array; OR'd with campaignId/brandId when matchAny is true
42
60
  * @param {string} [params.senderPhoneNumber] - Filter messages by the sender's 5-6 digit Short Code or 10+ digit phone number
43
61
  * @param {string} [params.recipientPhoneNumber] - Filter messages by the recipient's phone number
@@ -59,6 +77,7 @@ export class Messages {
59
77
  brandId,
60
78
  subgroupId,
61
79
  groupId,
80
+ registrationId,
62
81
  phoneNumber,
63
82
  senderPhoneNumber,
64
83
  recipientPhoneNumber,
@@ -66,9 +85,12 @@ export class Messages {
66
85
  direction,
67
86
  messageType,
68
87
  channel,
88
+ region,
89
+ regionScopes,
69
90
  matchAny,
70
91
  carrier,
71
92
  sentimentLabel,
93
+ errorCode,
72
94
  startDate,
73
95
  endDate,
74
96
  sortField,
@@ -78,8 +100,8 @@ export class Messages {
78
100
  dateBounds,
79
101
  options = {},
80
102
  }) {
81
- const filters = { id, campaignId, brandId, subgroupId, groupId, phoneNumber, senderPhoneNumber, recipientPhoneNumber, status, direction, messageType, channel, matchAny, carrier, sentimentLabel, startDate, endDate, sortField, sortOrder, page, limit, dateBounds };
82
- const queryString = this.client._getQueryString(filters);
103
+ const filters = { id, campaignId, brandId, subgroupId, groupId, registrationId, phoneNumber, senderPhoneNumber, recipientPhoneNumber, status, direction, messageType, channel, region, regionScopes, matchAny, carrier, sentimentLabel, errorCode, startDate, endDate, sortField, sortOrder, page, limit, dateBounds };
104
+ const queryString = this.client._getQueryString(withRegionScopes(filters));
83
105
  return this.client(`/message${queryString}`, { method: "GET", ...options });
84
106
  }
85
107
 
@@ -112,14 +134,17 @@ export class Messages {
112
134
  * @param {string|string[]} [params.subgroupId] - Filter analytics by the ID of the associated subgroup. Accepts a single value, an array, or a comma-separated string.
113
135
  * @param {string|string[]} [params.brandId] - Filter analytics by the ID of the associated brand. Accepts a single value, an array, or a comma-separated string.
114
136
  * @param {string|string[]} [params.campaignId] - Filter analytics by the ID of the associated campaign. Accepts a single value, an array, or a comma-separated string.
137
+ * @param {string|string[]} [params.registrationId] - Filter to traffic attributed to these registrations (hourly analytics only; a 400 while hourly reads are off). A phoneNumber filter takes precedence. Accepts a single value or an array.
115
138
  * @param {string|string[]} [params.phoneNumber] - Filter analytics by the phone number involved in the messages. Accepts a single value, an array, or a comma-separated string.
116
139
  * @param {string|string[]} [params.carrier] - Filter analytics by the carrier used for sending. Accepts a single value, an array, or a comma-separated string.
117
- * @param {string|string[]} [params.carrierFamily] - Filter analytics by the recipient's resolved carrier family (Default, ATT, TMobile, Verizon, USCellular, GoogleVoice, ClearSky, Interop, RogueMobile, P2P). Accepts a single value, an array, or a comma-separated string. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400 -- omit the parameter unless it is wanted.
140
+ * @param {string|string[]} [params.carrierFamily] - Filter analytics by the recipient's resolved carrier family (Default, ATT, TMobile, Verizon, USCellular, GoogleVoice, ClearSky, Interop, RogueMobile, P2P, Standard, IceWireless). Accepts a single value, an array, or a comma-separated string. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400 -- omit the parameter unless it is wanted.
118
141
  * @param {string} [params.startDate] - ISO-8601 date or timestamp; bound per dateBounds: a bare date is always that whole UTC day (inclusive); a timestamp is widened to its whole UTC day in "day" mode and bound as the instant it names, in whatever offset it was written, in "exact" mode
119
142
  * @param {string} [params.endDate] - ISO-8601 date or timestamp; bound per dateBounds: a bare date is always that whole UTC day (inclusive); a timestamp is widened to its whole UTC day in "day" mode and bound as the instant it names, in whatever offset it was written, in "exact" mode. In "exact" mode day buckets align to the UTC offset this bound carries, so a client that sends its own midnights gets its own calendar dates back
120
143
  * @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.
121
144
  * @param {(string|string[])} [params.messageType] - Message type(s) the SENTIMENT figures are scoped to: SMS, MMS or P2P (single value, array, or comma-separated string). Omit for all scored types. Does NOT narrow the message counts, which are always returned split per type (smsInbound/mmsInbound/p2pInbound) and have no filterable type dimension.
122
145
  * @param {string|string[]} [params.channel] - Filter analytics by channel (tenDLC, virtualLongCode, tollFree, shortCode, 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).
146
+ * @param {string|string[]} [params.region] - ISO-2 country filter: US, GB or CA (UK is accepted for GB); one value, an array, or a comma-separated string; omitted = every region. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
147
+ * @param {Object[]|string} [params.regionScopes] - Array of OR-ed branches `{ region, channels, brandId?, campaignId?, phoneNumber? }` (channels among tenDLC, virtualLongCode, tollFree, shortCode, p2p); `[]` matches nothing. Sent as JSON unless already a string. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
123
148
  * @param {("day"|"exact")} [params.dateBounds] - Which contract binds startDate/endDate. "day": each bound is widened to its whole UTC day. "exact": a timestamp is bound as the instant it names and a bare date is its whole UTC day. Omitted: "day".
124
149
  * @param {RequestOptions} [params.options] - Additional options for the request
125
150
  * @returns {Promise<SdkResponse<any>>} - A promise that resolves to the analytics data. Also includes inbound-message
@@ -131,9 +156,9 @@ export class Messages {
131
156
  * summed or re-averaged across types, rows or responses. To weight a subset of message types, pass
132
157
  * messageType and read sentimentScore.
133
158
  */
134
- async getAnalytics({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, carrierFamily, startDate, endDate, channel, messageType, matchAny, dateBounds, options = {} }) {
135
- const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, carrierFamily, startDate, endDate, channel, messageType, matchAny, dateBounds };
136
- const queryString = this.client._getQueryString(filters);
159
+ async getAnalytics({ groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, carrierFamily, startDate, endDate, channel, region, regionScopes, messageType, matchAny, dateBounds, options = {} }) {
160
+ const filters = { groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, carrierFamily, startDate, endDate, channel, region, regionScopes, messageType, matchAny, dateBounds };
161
+ const queryString = this.client._getQueryString(withRegionScopes(filters));
137
162
  return this.client(`/message/analytics${queryString}`, { method: "GET", ...options });
138
163
  }
139
164
 
@@ -146,13 +171,16 @@ export class Messages {
146
171
  * @param {string|string[]} [params.subgroupId] - Filter analytics by the ID of the associated subgroup. Accepts a single value, an array, or a comma-separated string.
147
172
  * @param {string|string[]} [params.brandId] - Filter analytics by the ID of the associated brand. Accepts a single value, an array, or a comma-separated string.
148
173
  * @param {string|string[]} [params.campaignId] - Filter analytics by the ID of the associated campaign. Accepts a single value, an array, or a comma-separated string.
174
+ * @param {string|string[]} [params.registrationId] - Filter to traffic attributed to these registrations (hourly analytics only; a 400 while hourly reads are off). A phoneNumber filter takes precedence. Accepts a single value or an array.
149
175
  * @param {string|string[]} [params.phoneNumber] - Filter analytics by the phone number involved in the messages. Accepts a single value, an array, or a comma-separated string.
150
176
  * @param {string|string[]} [params.carrier] - Filter analytics by the carrier used for sending. Accepts a single value, an array, or a comma-separated string.
151
- * @param {string|string[]} [params.carrierFamily] - Filter analytics by the recipient's resolved carrier family (Default, ATT, TMobile, Verizon, USCellular, GoogleVoice, ClearSky, Interop, RogueMobile, P2P). Accepts a single value, an array, or a comma-separated string. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400 -- omit the parameter unless it is wanted.
177
+ * @param {string|string[]} [params.carrierFamily] - Filter analytics by the recipient's resolved carrier family (Default, ATT, TMobile, Verizon, USCellular, GoogleVoice, ClearSky, Interop, RogueMobile, P2P, Standard, IceWireless). Accepts a single value, an array, or a comma-separated string. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400 -- omit the parameter unless it is wanted.
152
178
  * @param {string} [params.startDate] - ISO-8601 date or timestamp. It is bound per dateBounds: a bare date is always that whole UTC day (inclusive); a timestamp is widened to its whole UTC day in "day" mode and bound as the instant it names, in whatever offset it was written, in "exact" mode, then floored to the start of its hour at either granularity, because the hourly cube is keyed by hour and a mid-hour start would drop that hour's bucket.
153
179
  * @param {string} [params.endDate] - ISO-8601 date or timestamp. At day granularity it is bound per dateBounds: a bare date is always that whole UTC day (inclusive); a timestamp is widened to its whole UTC day in "day" mode and bound as the instant it names, in whatever offset it was written, in "exact" mode. In "exact" mode day buckets align to the UTC offset this bound carries, so a client that sends its own midnights gets its own calendar dates back; at hour granularity it is honoured as given.
154
180
  * @param {(string|string[])} [params.messageType] - Message type(s) the SENTIMENT figures are scoped to: SMS, MMS or P2P (single value, array, or comma-separated string). Omit for all scored types. Does NOT narrow the message counts, which are always returned split per type (smsInbound/mmsInbound/p2pInbound) and have no filterable type dimension.
155
181
  * @param {string|string[]} [params.channel] - Filter analytics by channel (tenDLC, virtualLongCode, tollFree, shortCode, 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.
182
+ * @param {string|string[]} [params.region] - ISO-2 country filter: US, GB or CA (UK is accepted for GB); one value, an array, or a comma-separated string; omitted = every region. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
183
+ * @param {Object[]|string} [params.regionScopes] - Array of OR-ed branches `{ region, channels, brandId?, campaignId?, phoneNumber? }` (channels among tenDLC, virtualLongCode, tollFree, shortCode, p2p); `[]` matches nothing. Sent as JSON unless already a string. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
156
184
  * @param {("day"|"hour")} [params.granularity] - Time-bucket grain of the byDate rows. Omit for day (each row's _id is a "YYYY-MM-DD" date). "hour" buckets by hour (each row's _id is a "YYYY-MM-DD HH:MM:SS" UTC hour) and is capped to a 7-day span. Only accepted where the environment serves hourly analytics; elsewhere any value, including "day", is rejected with a 400 -- omit the parameter unless hour grain is wanted.
157
185
  * @param {("carrier"|"carrierFamily")} [params.breakdown] - Adds a byBreakdown time × dimension series to the response ({ dimension, rows }: each row is one byDate bucket (_id) for one carrier or carrier family (key), over the top 50 keys by volume, 10DLC only) and caps the span at 31 days. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400 -- omit the parameter unless it is wanted.
158
186
  * @param {("day"|"exact")} [params.dateBounds] - Which contract binds startDate/endDate. "day": each bound is widened to its whole UTC day. "exact": a timestamp is bound as the instant it names and a bare date is its whole UTC day. Omitted: "day".
@@ -165,9 +193,9 @@ export class Messages {
165
193
  * score is divided server-side and the raw sums are never returned: a score is an average and must never be
166
194
  * summed or re-averaged across types, rows or responses.
167
195
  */
168
- async getAnalyticsDetail({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, carrierFamily, startDate, endDate, channel, messageType, granularity, breakdown, dateBounds, options = {} }) {
169
- const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, carrierFamily, startDate, endDate, channel, messageType, granularity, breakdown, dateBounds };
170
- const queryString = this.client._getQueryString(filters);
196
+ async getAnalyticsDetail({ groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, carrierFamily, startDate, endDate, channel, region, regionScopes, messageType, granularity, breakdown, dateBounds, options = {} }) {
197
+ const filters = { groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, carrierFamily, startDate, endDate, channel, region, regionScopes, messageType, granularity, breakdown, dateBounds };
198
+ const queryString = this.client._getQueryString(withRegionScopes(filters));
171
199
  return this.client(`/message/analytics/detail${queryString}`, { method: "GET", ...options });
172
200
  }
173
201
 
@@ -183,6 +211,7 @@ export class Messages {
183
211
  * @param {string} params.groupId - The group to scope the read to (required)
184
212
  * @param {string|string[]} [params.brandId] - Brand scope. Accepts a single value, an array, or a comma-separated string.
185
213
  * @param {string|string[]} [params.campaignId] - Campaign scope; wins over brandId. Accepts a single value, an array, or a comma-separated string.
214
+ * @param {string|string[]} [params.registrationId] - Filter to traffic attributed to these registrations (hourly analytics only; a 400 while hourly reads are off). Accepts a single value or an array.
186
215
  * @param {string|string[]} [params.carrierFamily] - Carrier-family filter (ATT, TMobile, Verizon, USCellular, ...). Accepts a single value, an array, or a comma-separated string.
187
216
  * @param {string} params.startDate - ISO-8601 date or timestamp. It is bound per dateBounds: a bare date is always that whole UTC day (inclusive); a timestamp is widened to its whole UTC day in "day" mode and bound as the instant it names, in whatever offset it was written, in "exact" mode, then floored to the start of its hour at hour granularity and of its minute at day granularity (the cube is keyed by minute).
188
217
  * @param {string} params.endDate - ISO-8601 date or timestamp. At hour granularity it is honoured as given; at day granularity it is bound per dateBounds: a bare date is always that whole UTC day (inclusive); a timestamp is widened to its whole UTC day in "day" mode and bound as the instant it names, in whatever offset it was written, in "exact" mode. In "exact" mode day buckets align to the UTC offset this bound carries, so a client that sends its own midnights gets its own calendar dates back. The span is capped at 35 days (the retention of the per-minute data).
@@ -192,8 +221,8 @@ export class Messages {
192
221
  * @param {RequestOptions} [params.options] - Additional options for the request
193
222
  * @returns {Promise<SdkResponse<any>>} - `{ totals, byDate, byCarrierFamily, byBreakdown: { dimension: "carrierFamily", rows } }`. Every row carries segments, messages, peakSegmentsPerMinute, peakMessagesPerMinute, peakMinute (UTC "YYYY-MM-DD HH:MM:SS", null when no traffic), sendingMinutes, averageSegmentsPerSendingMinute and minutesAtCeiling.
194
223
  */
195
- async getAnalyticsThroughput({ groupId, brandId, campaignId, carrierFamily, startDate, endDate, granularity, ceiling, dateBounds, options = {} }) {
196
- const filters = { groupId, brandId, campaignId, carrierFamily, startDate, endDate, granularity, ceiling, dateBounds };
224
+ async getAnalyticsThroughput({ groupId, brandId, campaignId, registrationId, carrierFamily, startDate, endDate, granularity, ceiling, dateBounds, options = {} }) {
225
+ const filters = { groupId, brandId, campaignId, registrationId, carrierFamily, startDate, endDate, granularity, ceiling, dateBounds };
197
226
  const queryString = this.client._getQueryString(filters);
198
227
  return this.client(`/message/analytics/throughput${queryString}`, { method: "GET", ...options });
199
228
  }
@@ -205,11 +234,12 @@ export class Messages {
205
234
  * @roles api, admin, developer, billing, user
206
235
  * @param {Object} params - The parameters for getting analytics filter options
207
236
  * @param {string} params.groupId - The ID of the group whose filter options to load
237
+ * @param {string|string[]} [params.region] - ISO-2 country filter: US, GB or CA (UK is accepted for GB); one value, an array, or a comma-separated string; omitted = every region. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
208
238
  * @param {RequestOptions} [params.options] - Additional options for the request
209
- * @returns {Promise<SdkResponse<any>>} - A promise that resolves to { subgroups, brands, campaigns, phoneNumbers }
239
+ * @returns {Promise<SdkResponse<any>>} - A promise that resolves to { subgroups, brands, campaigns, phoneNumbers }. Each phone number carries type (TOLL_FREE, SHORT_CODE, ALPHANUMERIC, VIRTUAL_LONG_NUMBER, ...) and country (ISO-2), null when unknown: TOLL_FREE, SHORT_CODE and ALPHANUMERIC are channels by type; any other US number is 10DLC and a non-US one is a Virtual Long Code.
210
240
  */
211
- async getAnalyticsFilterOptions({ groupId, options = {} }) {
212
- const filters = { groupId };
241
+ async getAnalyticsFilterOptions({ groupId, region, options = {} }) {
242
+ const filters = { groupId, region };
213
243
  const queryString = this.client._getQueryString(filters);
214
244
  return this.client(`/message/analytics/filter-options${queryString}`, { method: "GET", ...options });
215
245
  }
@@ -224,9 +254,10 @@ export class Messages {
224
254
  * @param {string|string[]} [params.subgroupId]
225
255
  * @param {string|string[]} [params.brandId]
226
256
  * @param {string|string[]} [params.campaignId]
257
+ * @param {string|string[]} [params.registrationId] - Filter to traffic attributed to these registrations (hourly analytics only; a 400 while hourly reads are off). A phoneNumber filter takes precedence. Accepts a single value or an array.
227
258
  * @param {string|string[]} [params.phoneNumber]
228
259
  * @param {string|string[]} [params.carrier]
229
- * @param {string|string[]} [params.carrierFamily] - Resolved carrier family of the recipient (Default, ATT, TMobile, Verizon, USCellular, GoogleVoice, ClearSky, Interop, RogueMobile, P2P); single value, array, or comma-separated. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400 -- omit the parameter unless it is wanted.
260
+ * @param {string|string[]} [params.carrierFamily] - Resolved carrier family of the recipient (Default, ATT, TMobile, Verizon, USCellular, GoogleVoice, ClearSky, Interop, RogueMobile, P2P, Standard, IceWireless); single value, array, or comma-separated. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400 -- omit the parameter unless it is wanted.
230
261
  * @param {string} [params.startDate]
231
262
  * @param {string} [params.endDate]
232
263
  * @param {number} [params.page=1]
@@ -234,13 +265,15 @@ export class Messages {
234
265
  * @param {("tenDLC"|"virtualLongCode"|"tollFree"|"shortCode"|"p2p"|"both")|Array<"tenDLC"|"virtualLongCode"|"tollFree"|"shortCode"|"p2p">} [params.channel="both"] - Filter and rank rows by the stored channel column. "both" (default) means all activity. tenDLC/virtualLongCode/tollFree/shortCode/p2p (single value or array) limit to the selected channel(s).
235
266
  * @param {(string|string[])} [params.messageType] - Message type(s) the SENTIMENT figures are scoped to: SMS, MMS or P2P (single value, array, or comma-separated string). Omit for all scored types. Does NOT narrow the message counts, which are always returned split per type (smsInbound/mmsInbound/p2pInbound) and have no filterable type dimension.
236
267
  * @param {("day"|"exact")} [params.dateBounds] - Which contract binds startDate/endDate. "day": each bound is widened to its whole UTC day. "exact": a timestamp is bound as the instant it names and a bare date is its whole UTC day. Omitted: "day".
268
+ * @param {string|string[]} [params.region] - ISO-2 country filter: US, GB or CA (UK is accepted for GB); one value, an array, or a comma-separated string; omitted = every region. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
269
+ * @param {Object[]|string} [params.regionScopes] - Array of OR-ed branches `{ region, channels, brandId?, campaignId?, phoneNumber? }` (channels among tenDLC, virtualLongCode, tollFree, shortCode, p2p); `[]` matches nothing. Sent as JSON unless already a string. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
237
270
  * @param {RequestOptions} [params.options]
238
271
  * @returns {Promise<SdkResponse<any>>} - { 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).
239
272
  * Each row also carries that subgroup's inbound-message sentiment: `sentimentScore` (volume-weighted average of every scored inbound message in that subgroup, -100..100, null when nothing was scored), `sentimentLabel`, `sentimentScoredCount`, `sentimentPositive`, `sentimentNeutral`, `sentimentNegative`, plus the same six per message type under `smsSentiment*`, `mmsSentiment*` and `p2pSentiment*` prefixes. The score is derived server-side and must never be re-averaged across rows — combine the counts, not the scores.
240
273
  */
241
- async getAnalyticsBySubgroup({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, carrierFamily, startDate, endDate, page, limit, channel, messageType, dateBounds, options = {} }) {
242
- const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, carrierFamily, startDate, endDate, page, limit, channel, messageType, dateBounds };
243
- const queryString = this.client._getQueryString(filters);
274
+ async getAnalyticsBySubgroup({ groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, carrierFamily, startDate, endDate, page, limit, channel, region, regionScopes, messageType, dateBounds, options = {} }) {
275
+ const filters = { groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, carrierFamily, startDate, endDate, page, limit, channel, region, regionScopes, messageType, dateBounds };
276
+ const queryString = this.client._getQueryString(withRegionScopes(filters));
244
277
  return this.client(`/message/analytics/by-subgroup${queryString}`, { method: "GET", ...options });
245
278
  }
246
279
 
@@ -254,21 +287,24 @@ export class Messages {
254
287
  * @param {string|string[]} [params.subgroupId]
255
288
  * @param {string|string[]} [params.brandId]
256
289
  * @param {string|string[]} [params.campaignId]
290
+ * @param {string|string[]} [params.registrationId] - Filter to traffic attributed to these registrations (hourly analytics only; a 400 while hourly reads are off). A phoneNumber filter takes precedence. Accepts a single value or an array.
257
291
  * @param {string|string[]} [params.phoneNumber]
258
292
  * @param {string|string[]} [params.carrier]
259
- * @param {string|string[]} [params.carrierFamily] - Resolved carrier family of the recipient (Default, ATT, TMobile, Verizon, USCellular, GoogleVoice, ClearSky, Interop, RogueMobile, P2P); single value, array, or comma-separated. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400 -- omit the parameter unless it is wanted.
293
+ * @param {string|string[]} [params.carrierFamily] - Resolved carrier family of the recipient (Default, ATT, TMobile, Verizon, USCellular, GoogleVoice, ClearSky, Interop, RogueMobile, P2P, Standard, IceWireless); single value, array, or comma-separated. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400 -- omit the parameter unless it is wanted.
260
294
  * @param {string} [params.startDate]
261
295
  * @param {string} [params.endDate]
262
296
  * @param {number} [params.page=1]
263
297
  * @param {number} [params.limit=50] - max 50 per page
264
298
  * @param {("tenDLC"|"virtualLongCode"|"tollFree"|"shortCode"|"p2p"|"both")|Array<"tenDLC"|"virtualLongCode"|"tollFree"|"shortCode"|"p2p">} [params.channel="both"] - Filter and rank rows by the stored channel column. "both" (default) means every code. tenDLC/virtualLongCode/tollFree/shortCode/p2p (single value or array) limit to the selected channel(s); when one channel is selected, totalErrors reflects only that channel.
265
299
  * @param {("day"|"exact")} [params.dateBounds] - Which contract binds startDate/endDate. "day": each bound is widened to its whole UTC day. "exact": a timestamp is bound as the instant it names and a bare date is its whole UTC day. Omitted: "day".
300
+ * @param {string|string[]} [params.region] - ISO-2 country filter: US, GB or CA (UK is accepted for GB); one value, an array, or a comma-separated string; omitted = every region. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
301
+ * @param {Object[]|string} [params.regionScopes] - Array of OR-ed branches `{ region, channels, brandId?, campaignId?, phoneNumber? }` (channels among tenDLC, virtualLongCode, tollFree, shortCode, p2p); `[]` matches nothing. Sent as JSON unless already a string. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
266
302
  * @param {RequestOptions} [params.options]
267
303
  * @returns {Promise<SdkResponse<any>>} - { rows, totalCount, totalErrors: { sms, mms, p2p, all }, page, limit }
268
304
  */
269
- async getAnalyticsByErrorCode({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, carrierFamily, startDate, endDate, page, limit, channel, dateBounds, options = {} }) {
270
- const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, carrierFamily, startDate, endDate, page, limit, channel, dateBounds };
271
- const queryString = this.client._getQueryString(filters);
305
+ async getAnalyticsByErrorCode({ groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, carrierFamily, startDate, endDate, page, limit, channel, region, regionScopes, dateBounds, options = {} }) {
306
+ const filters = { groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, carrierFamily, startDate, endDate, page, limit, channel, region, regionScopes, dateBounds };
307
+ const queryString = this.client._getQueryString(withRegionScopes(filters));
272
308
  return this.client(`/message/analytics/by-error-code${queryString}`, { method: "GET", ...options });
273
309
  }
274
310
 
@@ -281,18 +317,21 @@ export class Messages {
281
317
  * @param {string} [params.subgroupId] - Filter by the ID of the associated subgroup
282
318
  * @param {string} [params.brandId] - Filter by the ID of the associated brand
283
319
  * @param {string} [params.campaignId] - Filter by the ID of the associated campaign
320
+ * @param {string|string[]} [params.registrationId] - Filter to traffic attributed to these registrations (hourly analytics only; a 400 while hourly reads are off). A phoneNumber filter takes precedence. Accepts a single value or an array.
284
321
  * @param {string} [params.phoneNumber] - Filter by the phone number
285
322
  * @param {string} [params.carrier] - Filter by the carrier
286
323
  * @param {string} [params.startDate] - ISO-8601 date or timestamp; bound per dateBounds: a bare date is always that whole UTC day (inclusive); a timestamp is widened to its whole UTC day in "day" mode and bound as the instant it names, in whatever offset it was written, in "exact" mode
287
324
  * @param {string} [params.endDate] - ISO-8601 date or timestamp; bound per dateBounds: a bare date is always that whole UTC day (inclusive); a timestamp is widened to its whole UTC day in "day" mode and bound as the instant it names, in whatever offset it was written, in "exact" mode. In "exact" mode day buckets align to the UTC offset this bound carries, so a client that sends its own midnights gets its own calendar dates back
288
325
  * @param {string|string[]} [params.channel] - Filter by channel (tenDLC, virtualLongCode, tollFree, shortCode). 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.
289
326
  * @param {("day"|"exact")} [params.dateBounds] - Which contract binds startDate/endDate. "day": each bound is widened to its whole UTC day. "exact": a timestamp is bound as the instant it names and a bare date is its whole UTC day. Omitted: "day".
327
+ * @param {string|string[]} [params.region] - ISO-2 country filter: US, GB or CA (UK is accepted for GB); one value, an array, or a comma-separated string; omitted = every region. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
328
+ * @param {Object[]|string} [params.regionScopes] - Array of OR-ed branches `{ region, channels, brandId?, campaignId?, phoneNumber? }` (channels among tenDLC, virtualLongCode, tollFree, shortCode, p2p); `[]` matches nothing. Sent as JSON unless already a string. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
290
329
  * @param {RequestOptions} [params.options] - Additional options for the request
291
- * @returns {Promise<SdkResponse<any>>} - A promise that resolves to the DNC analytics data (totals, byDate, byPhoneNumber, byCarrier, byKeyword). byKeyword breaks opt-outs down by the normalized keyword that revoked consent ({ optOutKeyword, total, sms, mms }); opt-outs recorded before keyword capture shipped appear as a single optOutKeyword: null bucket ("not recorded"). The distinct keyword set is open-ended (campaigns register their own keywords beyond the mandatory floor) — render top-N plus Other, never a fixed list.
330
+ * @returns {Promise<SdkResponse<any>>} - A promise that resolves to the DNC analytics data (totals, byDate, byPhoneNumber, bySenderNumber, byCampaign, bySubgroup, byType, byCarrier, byKeyword). bySenderNumber ({ senderPhoneNumber, total, sms, mms }) attributes each opt-out to the first business number that received it, so it is unchanged by later campaign moves and START replies. byCampaign ({ campaignId, ... }) counts campaign-scoped opt-outs only, by the campaign at the time of the STOP; subgroup-scoped opt-outs (non-US recipients) are never attributed to a campaign and appear under bySubgroup ({ subgroupId, ... }) instead. byType ({ messageType, total }) splits SMS/MMS. byKeyword breaks opt-outs down by the normalized keyword that revoked consent ({ optOutKeyword, total, sms, mms }); opt-outs recorded before keyword capture shipped appear as a single optOutKeyword: null bucket ("not recorded"). The distinct keyword set is open-ended (campaigns register their own keywords beyond the mandatory floor) — render top-N plus Other, never a fixed list.
292
331
  */
293
- async getDncAnalytics({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, channel, dateBounds, options = {} }) {
294
- const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, channel, dateBounds };
295
- const queryString = this.client._getQueryString(filters);
332
+ async getDncAnalytics({ groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, startDate, endDate, channel, region, regionScopes, dateBounds, options = {} }) {
333
+ const filters = { groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, startDate, endDate, channel, region, regionScopes, dateBounds };
334
+ const queryString = this.client._getQueryString(withRegionScopes(filters));
296
335
  return this.client(`/message/dnc/analytics${queryString}`, { method: "GET", ...options });
297
336
  }
298
337
 
@@ -305,6 +344,7 @@ export class Messages {
305
344
  * @param {string} [params.subgroupId] - Filter by the ID of the associated subgroup
306
345
  * @param {string} [params.brandId] - Filter by the ID of the associated brand
307
346
  * @param {string} [params.campaignId] - Filter by the ID of the associated campaign
347
+ * @param {string|string[]} [params.registrationId] - Filter to traffic attributed to these registrations (hourly analytics only; a 400 while hourly reads are off). A phoneNumber filter takes precedence. Accepts a single value or an array.
308
348
  * @param {string} [params.phoneNumber] - Filter by the phone number
309
349
  * @param {string} [params.carrier] - Filter by the carrier
310
350
  * @param {string} [params.startDate] - ISO-8601 date or timestamp; bound per dateBounds: a bare date is always that whole UTC day (inclusive); a timestamp is widened to its whole UTC day in "day" mode and bound as the instant it names, in whatever offset it was written, in "exact" mode
@@ -315,12 +355,14 @@ export class Messages {
315
355
  * @param {string} [params.sortOrder] - Sort direction (asc, desc)
316
356
  * @param {string|string[]} [params.channel] - Filter by channel (tenDLC, virtualLongCode, tollFree, shortCode). 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.
317
357
  * @param {("day"|"exact")} [params.dateBounds] - Which contract binds startDate/endDate. "day": each bound is widened to its whole UTC day. "exact": a timestamp is bound as the instant it names and a bare date is its whole UTC day. Omitted: "day".
358
+ * @param {string|string[]} [params.region] - ISO-2 country filter: US, GB or CA (UK is accepted for GB); one value, an array, or a comma-separated string; omitted = every region. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
359
+ * @param {Object[]|string} [params.regionScopes] - Array of OR-ed branches `{ region, channels, brandId?, campaignId?, phoneNumber? }` (channels among tenDLC, virtualLongCode, tollFree, shortCode, p2p); `[]` matches nothing. Sent as JSON unless already a string. Only accepted where the environment serves hourly analytics; elsewhere any value is rejected with a 400.
318
360
  * @param {RequestOptions} [params.options] - Additional options for the request
319
- * @returns {Promise<SdkResponse<any>>} - A promise that resolves to the paginated DNC records. Each record carries optOutKeyword — the normalized keyword that revoked consent (e.g. "stop", "opt out"; a repeat opt-out records the most recent word), null for opt-outs recorded before keyword capture shipped — and carrierFamily, the resolved carrier family of the recipient number (Default, ATT, TMobile, Verizon, USCellular, GoogleVoice, ClearSky, Interop, RogueMobile), copied from the inbound message that triggered the opt-out.
361
+ * @returns {Promise<SdkResponse<any>>} - A promise that resolves to the paginated DNC records. Each record carries senderPhoneNumber — the first business number that received the opt-out (set once, never changed by a later STOP or a campaign move; the same value as phoneNumber) — optOutKeyword — the normalized keyword that revoked consent (e.g. "stop", "opt out"; a repeat opt-out records the most recent word), null for opt-outs recorded before keyword capture shipped — and carrierFamily, the resolved carrier family of the recipient number (Default, ATT, TMobile, Verizon, USCellular, GoogleVoice, ClearSky, Interop, RogueMobile, Standard, IceWireless), copied from the inbound message that triggered the opt-out. campaignId is null on subgroup-scoped records (non-US recipients).
320
362
  */
321
- async getDncRecords({ groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, page, limit, sortField, sortOrder, channel, dateBounds, options = {} }) {
322
- const filters = { groupId, subgroupId, brandId, campaignId, phoneNumber, carrier, startDate, endDate, page, limit, sortField, sortOrder, channel, dateBounds };
323
- const queryString = this.client._getQueryString(filters);
363
+ async getDncRecords({ groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, startDate, endDate, page, limit, sortField, sortOrder, channel, region, regionScopes, dateBounds, options = {} }) {
364
+ const filters = { groupId, subgroupId, brandId, campaignId, registrationId, phoneNumber, carrier, startDate, endDate, page, limit, sortField, sortOrder, channel, region, regionScopes, dateBounds };
365
+ const queryString = this.client._getQueryString(withRegionScopes(filters));
324
366
  return this.client(`/message/dnc${queryString}`, { method: "GET", ...options });
325
367
  }
326
368
 
@@ -77,6 +77,7 @@ export class Numbers {
77
77
  * @param {Object} params - The parameters for filtering the phone numbers
78
78
  * @param {string} [params.phoneNumber] - Filter by phone number (partial match)
79
79
  * @param {string} [params.campaignId] - Filter by campaign ID
80
+ * @param {string} [params.registrationId] - Filter to numbers provisioned under this registration.
80
81
  * @param {string} [params.brandId] - Filter by brand ID
81
82
  * @param {string} [params.subgroupId] - Filter by subgroup ID
82
83
  * @param {string} [params.groupId] - Filter by group ID
@@ -102,8 +103,8 @@ export class Numbers {
102
103
  * or GET /campaign/health.
103
104
  * @returns {Promise<SdkResponse<any>>} A promise that resolves to the list of phone numbers
104
105
  */
105
- async getPhoneNumbers({ phoneNumber, campaignId, brandId, subgroupId, groupId, page, limit, options = {} }) {
106
- const filters = { phoneNumber, campaignId, brandId, subgroupId, groupId, page, limit };
106
+ async getPhoneNumbers({ phoneNumber, campaignId, registrationId, brandId, subgroupId, groupId, page, limit, options = {} }) {
107
+ const filters = { phoneNumber, campaignId, registrationId, brandId, subgroupId, groupId, page, limit };
107
108
  const queryString = this.client._getQueryString(filters);
108
109
  return this.client(`/number${queryString}`, { method: 'GET', ...options });
109
110
  }
@@ -134,7 +135,7 @@ export class Numbers {
134
135
  * @param {boolean} [params.voiceEnabled] - Filter for phone numbers that are voice enabled
135
136
  * @param {string} [params.country] - Filter by country code (e.g., "US")
136
137
  * @param {string} [params.state] - Filter by state code (e.g., "CA")
137
- * @param {string} [params.city] - City prefix; requires country US/CA and state/province.
138
+ * @param {string} [params.city] - City prefix; requires country US and state.
138
139
  * @param {string} [params.npa] - Filter by NPA (area code)
139
140
  * @param {string} [params.nxx] - Filter by NXX (central office code) - the first three digits of the local phone number after the area code
140
141
  * @param {string} [params.phoneNumber] - Filter by phone number
@@ -172,7 +173,7 @@ export class Numbers {
172
173
  * @param {Object} params - The parameters for purchasing phone numbers
173
174
  * @param {string[]} params.phoneNumbers - The list of phone numbers to purchase
174
175
  * @param {string} params.subgroupId - The ID of the subgroup to assign the purchased phone numbers to
175
- * @param {'US'|'CA'} [params.country='US'] - ISO-2 purchase country. Toll-Free always uses the shared registry.
176
+ * @param {string} [params.country='US'] - ISO-2 purchase country; US.
176
177
  * @param {RequestOptions} [params.options] - Additional options for the request
177
178
  * @throws {Error} Throws an error if the phoneNumbers or subgroupId parameter is missing
178
179
  * @returns {Promise<SdkResponse<any>>} A promise that resolves to `{ message }` once the request is queued.
@@ -193,7 +194,7 @@ export class Numbers {
193
194
  * @param {Object} params - The parameters for purchasing toll-free numbers
194
195
  * @param {number} params.quantity - The number of toll-free numbers to purchase (1-10)
195
196
  * @param {string} params.subgroupId - The subgroup the purchased numbers are assigned to
196
- * @param {'US'|'CA'} [params.country='US'] - ISO-2 purchase country. Toll-Free always uses the shared registry.
197
+ * @param {string} [params.country='US'] - ISO-2 purchase country; US.
197
198
  * @param {RequestOptions} [params.options] - Additional options for the request
198
199
  * @throws {Error} Throws an error if the quantity or subgroupId parameter is missing
199
200
  * @returns {Promise<SdkResponse<any>>} A promise that resolves to `{ message, orderId }` once the request is queued.