sendblue 2.1.0 → 3.3.1

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.
Files changed (126) hide show
  1. package/CHANGELOG.md +174 -0
  2. package/LICENSE +1 -1
  3. package/README.md +34 -5
  4. package/client.d.mts +25 -3
  5. package/client.d.mts.map +1 -1
  6. package/client.d.ts +25 -3
  7. package/client.d.ts.map +1 -1
  8. package/client.js +44 -19
  9. package/client.js.map +1 -1
  10. package/client.mjs +44 -19
  11. package/client.mjs.map +1 -1
  12. package/internal/parse.d.mts.map +1 -1
  13. package/internal/parse.d.ts.map +1 -1
  14. package/internal/parse.js +5 -0
  15. package/internal/parse.js.map +1 -1
  16. package/internal/parse.mjs +5 -0
  17. package/internal/parse.mjs.map +1 -1
  18. package/internal/utils/query.d.mts +5 -0
  19. package/internal/utils/query.d.mts.map +1 -0
  20. package/internal/utils/query.d.ts +5 -0
  21. package/internal/utils/query.d.ts.map +1 -0
  22. package/internal/utils/query.js +23 -0
  23. package/internal/utils/query.js.map +1 -0
  24. package/internal/utils/query.mjs +20 -0
  25. package/internal/utils/query.mjs.map +1 -0
  26. package/internal/utils.d.mts +1 -0
  27. package/internal/utils.d.ts +1 -0
  28. package/internal/utils.js +1 -0
  29. package/internal/utils.js.map +1 -1
  30. package/internal/utils.mjs +1 -0
  31. package/package.json +1 -1
  32. package/resources/contacts/bulk.d.mts +25 -3
  33. package/resources/contacts/bulk.d.mts.map +1 -1
  34. package/resources/contacts/bulk.d.ts +25 -3
  35. package/resources/contacts/bulk.d.ts.map +1 -1
  36. package/resources/contacts/bulk.js +3 -0
  37. package/resources/contacts/bulk.js.map +1 -1
  38. package/resources/contacts/bulk.mjs +3 -0
  39. package/resources/contacts/bulk.mjs.map +1 -1
  40. package/resources/contacts/contacts.d.mts +105 -18
  41. package/resources/contacts/contacts.d.mts.map +1 -1
  42. package/resources/contacts/contacts.d.ts +105 -18
  43. package/resources/contacts/contacts.d.ts.map +1 -1
  44. package/resources/contacts/contacts.js +5 -2
  45. package/resources/contacts/contacts.js.map +1 -1
  46. package/resources/contacts/contacts.mjs +5 -2
  47. package/resources/contacts/contacts.mjs.map +1 -1
  48. package/resources/contacts/index.d.mts +1 -1
  49. package/resources/contacts/index.d.mts.map +1 -1
  50. package/resources/contacts/index.d.ts +1 -1
  51. package/resources/contacts/index.d.ts.map +1 -1
  52. package/resources/contacts/index.js.map +1 -1
  53. package/resources/contacts/index.mjs.map +1 -1
  54. package/resources/groups.d.mts +3 -0
  55. package/resources/groups.d.mts.map +1 -1
  56. package/resources/groups.d.ts +3 -0
  57. package/resources/groups.d.ts.map +1 -1
  58. package/resources/groups.js +3 -0
  59. package/resources/groups.js.map +1 -1
  60. package/resources/groups.mjs +3 -0
  61. package/resources/groups.mjs.map +1 -1
  62. package/resources/index.d.mts +1 -1
  63. package/resources/index.d.mts.map +1 -1
  64. package/resources/index.d.ts +1 -1
  65. package/resources/index.d.ts.map +1 -1
  66. package/resources/index.js.map +1 -1
  67. package/resources/index.mjs.map +1 -1
  68. package/resources/lookups.d.mts +3 -0
  69. package/resources/lookups.d.mts.map +1 -1
  70. package/resources/lookups.d.ts +3 -0
  71. package/resources/lookups.d.ts.map +1 -1
  72. package/resources/lookups.js +3 -0
  73. package/resources/lookups.js.map +1 -1
  74. package/resources/lookups.mjs +3 -0
  75. package/resources/lookups.mjs.map +1 -1
  76. package/resources/media-objects.d.mts +3 -0
  77. package/resources/media-objects.d.mts.map +1 -1
  78. package/resources/media-objects.d.ts +3 -0
  79. package/resources/media-objects.d.ts.map +1 -1
  80. package/resources/media-objects.js +3 -0
  81. package/resources/media-objects.js.map +1 -1
  82. package/resources/media-objects.mjs +3 -0
  83. package/resources/media-objects.mjs.map +1 -1
  84. package/resources/messages.d.mts +50 -7
  85. package/resources/messages.d.mts.map +1 -1
  86. package/resources/messages.d.ts +50 -7
  87. package/resources/messages.d.ts.map +1 -1
  88. package/resources/messages.js +19 -0
  89. package/resources/messages.js.map +1 -1
  90. package/resources/messages.mjs +19 -0
  91. package/resources/messages.mjs.map +1 -1
  92. package/resources/typing-indicators.d.mts +10 -2
  93. package/resources/typing-indicators.d.mts.map +1 -1
  94. package/resources/typing-indicators.d.ts +10 -2
  95. package/resources/typing-indicators.d.ts.map +1 -1
  96. package/resources/typing-indicators.js +5 -2
  97. package/resources/typing-indicators.js.map +1 -1
  98. package/resources/typing-indicators.mjs +5 -2
  99. package/resources/typing-indicators.mjs.map +1 -1
  100. package/resources/webhooks.d.mts +149 -145
  101. package/resources/webhooks.d.mts.map +1 -1
  102. package/resources/webhooks.d.ts +149 -145
  103. package/resources/webhooks.d.ts.map +1 -1
  104. package/resources/webhooks.js +11 -57
  105. package/resources/webhooks.js.map +1 -1
  106. package/resources/webhooks.mjs +11 -57
  107. package/resources/webhooks.mjs.map +1 -1
  108. package/src/client.ts +51 -24
  109. package/src/internal/parse.ts +6 -0
  110. package/src/internal/utils/query.ts +23 -0
  111. package/src/internal/utils.ts +1 -0
  112. package/src/resources/contacts/bulk.ts +24 -3
  113. package/src/resources/contacts/contacts.ts +118 -18
  114. package/src/resources/contacts/index.ts +1 -0
  115. package/src/resources/groups.ts +3 -0
  116. package/src/resources/index.ts +1 -0
  117. package/src/resources/lookups.ts +3 -0
  118. package/src/resources/media-objects.ts +3 -0
  119. package/src/resources/messages.ts +52 -7
  120. package/src/resources/typing-indicators.ts +11 -2
  121. package/src/resources/webhooks.ts +185 -154
  122. package/src/version.ts +1 -1
  123. package/version.d.mts +1 -1
  124. package/version.d.ts +1 -1
  125. package/version.js +1 -1
  126. package/version.mjs +1 -1
package/src/client.ts CHANGED
@@ -11,6 +11,7 @@ import type { APIResponseProps } from './internal/parse';
11
11
  import { getPlatformHeaders } from './internal/detect-platform';
12
12
  import * as Shims from './internal/shims';
13
13
  import * as Opts from './internal/request-options';
14
+ import { stringifyQuery } from './internal/utils/query';
14
15
  import { VERSION } from './version';
15
16
  import * as Errors from './core/error';
16
17
  import * as Uploads from './core/uploads';
@@ -51,6 +52,7 @@ import {
51
52
  ContactCreateParams,
52
53
  ContactCreateResponse,
53
54
  ContactDeleteResponse,
55
+ ContactListParams,
54
56
  ContactListResponse,
55
57
  ContactRetrieveResponse,
56
58
  ContactUpdateParams,
@@ -279,21 +281,8 @@ export class SendblueAPI {
279
281
  /**
280
282
  * Basic re-implementation of `qs.stringify` for primitive types.
281
283
  */
282
- protected stringifyQuery(query: Record<string, unknown>): string {
283
- return Object.entries(query)
284
- .filter(([_, value]) => typeof value !== 'undefined')
285
- .map(([key, value]) => {
286
- if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
287
- return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
288
- }
289
- if (value === null) {
290
- return `${encodeURIComponent(key)}=`;
291
- }
292
- throw new Errors.SendblueAPIError(
293
- `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`,
294
- );
295
- })
296
- .join('&');
284
+ protected stringifyQuery(query: object | Record<string, unknown>): string {
285
+ return stringifyQuery(query);
297
286
  }
298
287
 
299
288
  private getUserAgent(): string {
@@ -325,12 +314,13 @@ export class SendblueAPI {
325
314
  : new URL(baseURL + (baseURL.endsWith('/') && path.startsWith('/') ? path.slice(1) : path));
326
315
 
327
316
  const defaultQuery = this.defaultQuery();
328
- if (!isEmptyObj(defaultQuery)) {
329
- query = { ...defaultQuery, ...query };
317
+ const pathQuery = Object.fromEntries(url.searchParams);
318
+ if (!isEmptyObj(defaultQuery) || !isEmptyObj(pathQuery)) {
319
+ query = { ...pathQuery, ...defaultQuery, ...query };
330
320
  }
331
321
 
332
322
  if (typeof query === 'object' && query && !Array.isArray(query)) {
333
- url.search = this.stringifyQuery(query as Record<string, unknown>);
323
+ url.search = this.stringifyQuery(query);
334
324
  }
335
325
 
336
326
  return url.toString();
@@ -514,7 +504,7 @@ export class SendblueAPI {
514
504
  loggerFor(this).info(`${responseInfo} - ${retryMessage}`);
515
505
 
516
506
  const errText = await response.text().catch((err: any) => castToError(err).message);
517
- const errJSON = safeJSON(errText);
507
+ const errJSON = safeJSON(errText) as any;
518
508
  const errMessage = errJSON ? undefined : errText;
519
509
 
520
510
  loggerFor(this).debug(
@@ -555,9 +545,10 @@ export class SendblueAPI {
555
545
  controller: AbortController,
556
546
  ): Promise<Response> {
557
547
  const { signal, method, ...options } = init || {};
558
- if (signal) signal.addEventListener('abort', () => controller.abort());
548
+ const abort = this._makeAbort(controller);
549
+ if (signal) signal.addEventListener('abort', abort, { once: true });
559
550
 
560
- const timeout = setTimeout(() => controller.abort(), ms);
551
+ const timeout = setTimeout(abort, ms);
561
552
 
562
553
  const isReadableBody =
563
554
  ((globalThis as any).ReadableStream && options.body instanceof (globalThis as any).ReadableStream) ||
@@ -634,9 +625,9 @@ export class SendblueAPI {
634
625
  }
635
626
  }
636
627
 
637
- // If the API asks us to wait a certain amount of time (and it's a reasonable amount),
638
- // just do what it says, but otherwise calculate a default
639
- if (!(timeoutMillis && 0 <= timeoutMillis && timeoutMillis < 60 * 1000)) {
628
+ // If the API asks us to wait a certain amount of time, just do what it
629
+ // says, but otherwise calculate a default
630
+ if (timeoutMillis === undefined) {
640
631
  const maxRetries = options.maxRetries ?? this.maxRetries;
641
632
  timeoutMillis = this.calculateDefaultRetryTimeoutMillis(retriesRemaining, maxRetries);
642
633
  }
@@ -724,6 +715,12 @@ export class SendblueAPI {
724
715
  return headers.values;
725
716
  }
726
717
 
718
+ private _makeAbort(controller: AbortController) {
719
+ // note: we can't just inline this method inside `fetchWithTimeout()` because then the closure
720
+ // would capture all request options, and cause a memory leak.
721
+ return () => controller.abort();
722
+ }
723
+
727
724
  private buildBody({ options: { body, headers: rawHeaders } }: { options: FinalRequestOptions }): {
728
725
  bodyHeaders: HeadersLike;
729
726
  body: BodyInit | undefined;
@@ -756,6 +753,14 @@ export class SendblueAPI {
756
753
  (Symbol.iterator in body && 'next' in body && typeof body.next === 'function'))
757
754
  ) {
758
755
  return { bodyHeaders: undefined, body: Shims.ReadableStreamFrom(body as AsyncIterable<Uint8Array>) };
756
+ } else if (
757
+ typeof body === 'object' &&
758
+ headers.values.get('content-type') === 'application/x-www-form-urlencoded'
759
+ ) {
760
+ return {
761
+ bodyHeaders: { 'content-type': 'application/x-www-form-urlencoded' },
762
+ body: this.stringifyQuery(body),
763
+ };
759
764
  } else {
760
765
  return this.#encoder({ body, headers });
761
766
  }
@@ -780,12 +785,33 @@ export class SendblueAPI {
780
785
 
781
786
  static toFile = Uploads.toFile;
782
787
 
788
+ /**
789
+ * Operations for sending and managing messages
790
+ */
783
791
  messages: API.Messages = new API.Messages(this);
792
+ /**
793
+ * Operations for group messaging (beta)
794
+ */
784
795
  groups: API.Groups = new API.Groups(this);
796
+ /**
797
+ * Operations for uploading and managing media files
798
+ */
785
799
  mediaObjects: API.MediaObjects = new API.MediaObjects(this);
800
+ /**
801
+ * Operations for looking up service availability for phone numbers
802
+ */
786
803
  lookups: API.Lookups = new API.Lookups(this);
804
+ /**
805
+ * Operations for sending and managing messages
806
+ */
787
807
  typingIndicators: API.TypingIndicators = new API.TypingIndicators(this);
808
+ /**
809
+ * Operations for managing contacts
810
+ */
788
811
  contacts: API.Contacts = new API.Contacts(this);
812
+ /**
813
+ * Operations for managing webhook subscriptions
814
+ */
789
815
  webhooks: API.Webhooks = new API.Webhooks(this);
790
816
  }
791
817
 
@@ -848,6 +874,7 @@ export declare namespace SendblueAPI {
848
874
  type ContactVerifyResponse as ContactVerifyResponse,
849
875
  type ContactCreateParams as ContactCreateParams,
850
876
  type ContactUpdateParams as ContactUpdateParams,
877
+ type ContactListParams as ContactListParams,
851
878
  type ContactVerifyParams as ContactVerifyParams,
852
879
  };
853
880
 
@@ -29,6 +29,12 @@ export async function defaultParseResponse<T>(client: SendblueAPI, props: APIRes
29
29
  const mediaType = contentType?.split(';')[0]?.trim();
30
30
  const isJSON = mediaType?.includes('application/json') || mediaType?.endsWith('+json');
31
31
  if (isJSON) {
32
+ const contentLength = response.headers.get('content-length');
33
+ if (contentLength === '0') {
34
+ // if there is no content we can't do anything
35
+ return undefined as T;
36
+ }
37
+
32
38
  const json = await response.json();
33
39
  return json as T;
34
40
  }
@@ -0,0 +1,23 @@
1
+ // File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2
+
3
+ import { SendblueAPIError } from '../../core/error';
4
+
5
+ /**
6
+ * Basic re-implementation of `qs.stringify` for primitive types.
7
+ */
8
+ export function stringifyQuery(query: object | Record<string, unknown>) {
9
+ return Object.entries(query)
10
+ .filter(([_, value]) => typeof value !== 'undefined')
11
+ .map(([key, value]) => {
12
+ if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {
13
+ return `${encodeURIComponent(key)}=${encodeURIComponent(value)}`;
14
+ }
15
+ if (value === null) {
16
+ return `${encodeURIComponent(key)}=`;
17
+ }
18
+ throw new SendblueAPIError(
19
+ `Cannot stringify type ${typeof value}; Expected string, number, boolean, or null. If you need to pass nested query parameters, you can manually encode them, e.g. { query: { 'foo[key1]': value1, 'foo[key2]': value2 } }, and please open a GitHub issue requesting better support for your use case.`,
20
+ );
21
+ })
22
+ .join('&');
23
+ }
@@ -6,3 +6,4 @@ export * from './utils/env';
6
6
  export * from './utils/log';
7
7
  export * from './utils/uuid';
8
8
  export * from './utils/sleep';
9
+ export * from './utils/query';
@@ -5,6 +5,9 @@ import * as ContactsAPI from './contacts';
5
5
  import { APIPromise } from '../../core/api-promise';
6
6
  import { RequestOptions } from '../../internal/request-options';
7
7
 
8
+ /**
9
+ * Operations for managing contacts
10
+ */
8
11
  export class Bulk extends APIResource {
9
12
  /**
10
13
  * Create multiple contacts in bulk
@@ -56,13 +59,31 @@ export interface BulkCreateParams {
56
59
 
57
60
  export namespace BulkCreateParams {
58
61
  export interface Contact {
62
+ /**
63
+ * Phone number in E.164 format
64
+ */
59
65
  phone: string;
60
66
 
61
- company?: string;
67
+ /**
68
+ * Company name
69
+ */
70
+ company_name?: string;
62
71
 
63
- firstName?: string;
72
+ /**
73
+ * Custom key-value pairs. Keys are human-readable labels; new labels are
74
+ * auto-created.
75
+ */
76
+ custom_variables?: { [key: string]: string };
64
77
 
65
- lastName?: string;
78
+ /**
79
+ * Contact's first name
80
+ */
81
+ first_name?: string;
82
+
83
+ /**
84
+ * Contact's last name
85
+ */
86
+ last_name?: string;
66
87
 
67
88
  tags?: Array<string>;
68
89
  }
@@ -7,6 +7,9 @@ import { APIPromise } from '../../core/api-promise';
7
7
  import { RequestOptions } from '../../internal/request-options';
8
8
  import { path } from '../../internal/utils/path';
9
9
 
10
+ /**
11
+ * Operations for managing contacts
12
+ */
10
13
  export class Contacts extends APIResource {
11
14
  bulk: BulkAPI.Bulk = new BulkAPI.Bulk(this._client);
12
15
 
@@ -62,8 +65,11 @@ export class Contacts extends APIResource {
62
65
  * const contacts = await client.contacts.list();
63
66
  * ```
64
67
  */
65
- list(options?: RequestOptions): APIPromise<ContactListResponse> {
66
- return this._client.get('/api/v2/contacts', options);
68
+ list(
69
+ query: ContactListParams | null | undefined = {},
70
+ options?: RequestOptions,
71
+ ): APIPromise<ContactListResponse> {
72
+ return this._client.get('/api/v2/contacts', { query, ...options });
67
73
  }
68
74
 
69
75
  /**
@@ -109,27 +115,32 @@ export interface Contact {
109
115
  /**
110
116
  * Email of assigned user
111
117
  */
112
- assignedToEmail?: string;
118
+ assigned_to_email?: string;
113
119
 
114
120
  /**
115
121
  * Company name
116
122
  */
117
- companyName?: string;
123
+ company_name?: string;
118
124
 
119
125
  /**
120
126
  * When the contact was created
121
127
  */
122
128
  created_at?: string;
123
129
 
130
+ /**
131
+ * Custom key-value pairs stored on the contact. Keys are human-readable labels.
132
+ */
133
+ custom_variables?: { [key: string]: string };
134
+
124
135
  /**
125
136
  * First name
126
137
  */
127
- firstName?: string;
138
+ first_name?: string;
128
139
 
129
140
  /**
130
141
  * Last name
131
142
  */
132
- lastName?: string;
143
+ last_name?: string;
133
144
 
134
145
  /**
135
146
  * Phone number in E.164 format
@@ -139,12 +150,17 @@ export interface Contact {
139
150
  /**
140
151
  * Associated Sendblue phone number
141
152
  */
142
- sendblueNumber?: string;
153
+ sendblue_number?: string;
143
154
 
144
155
  /**
145
156
  * Tags associated with the contact
146
157
  */
147
158
  tags?: Array<string>;
159
+
160
+ /**
161
+ * Whether the contact is verified
162
+ */
163
+ verified?: boolean;
148
164
  }
149
165
 
150
166
  export interface ContactCreateResponse {
@@ -184,57 +200,63 @@ export interface ContactVerifyResponse {
184
200
 
185
201
  export interface ContactCreateParams {
186
202
  /**
187
- * Contact's phone number in E.164 format
203
+ * Contact's phone number in E.164 format (preferred)
188
204
  */
189
205
  number: string;
190
206
 
191
207
  /**
192
- * Email of assigned user
208
+ * Email of assigned user (preferred)
193
209
  */
194
210
  assigned_to_email?: string;
195
211
 
196
212
  /**
197
- * Email of assigned user (alternative)
213
+ * @deprecated Email of assigned user (deprecated, use assigned_to_email)
198
214
  */
199
215
  assignedToEmail?: string;
200
216
 
201
217
  /**
202
- * Contact's first name
218
+ * Custom key-value pairs. Keys are human-readable labels; new labels are
219
+ * auto-created.
220
+ */
221
+ custom_variables?: { [key: string]: string };
222
+
223
+ /**
224
+ * Contact's first name (preferred)
203
225
  */
204
226
  first_name?: string;
205
227
 
206
228
  /**
207
- * Contact's first name (alternative)
229
+ * @deprecated Contact's first name (deprecated, use first_name)
208
230
  */
209
231
  firstName?: string;
210
232
 
211
233
  /**
212
- * Contact's last name
234
+ * Contact's last name (preferred)
213
235
  */
214
236
  last_name?: string;
215
237
 
216
238
  /**
217
- * Contact's last name (alternative)
239
+ * @deprecated Contact's last name (deprecated, use last_name)
218
240
  */
219
241
  lastName?: string;
220
242
 
221
243
  /**
222
- * Contact's phone number (alternative)
244
+ * @deprecated Contact's phone number (deprecated, use number)
223
245
  */
224
246
  phone_number?: string;
225
247
 
226
248
  /**
227
- * Contact's phone number (alternative)
249
+ * @deprecated Contact's phone number (deprecated, use number)
228
250
  */
229
251
  phoneNumber?: string;
230
252
 
231
253
  /**
232
- * Associated Sendblue phone number
254
+ * Associated Sendblue phone number to send with (preferred)
233
255
  */
234
256
  sendblue_number?: string;
235
257
 
236
258
  /**
237
- * Associated Sendblue phone number (alternative)
259
+ * @deprecated Associated Sendblue phone number (deprecated, use sendblue_number)
238
260
  */
239
261
  sendblueNumber?: string;
240
262
 
@@ -250,19 +272,96 @@ export interface ContactCreateParams {
250
272
  }
251
273
 
252
274
  export interface ContactUpdateParams {
275
+ /**
276
+ * Email of assigned user (preferred)
277
+ */
278
+ assigned_to_email?: string;
279
+
280
+ /**
281
+ * @deprecated Deprecated, use assigned_to_email
282
+ */
253
283
  assignedToEmail?: string;
254
284
 
285
+ /**
286
+ * Company name (preferred)
287
+ */
288
+ company_name?: string;
289
+
290
+ /**
291
+ * @deprecated Deprecated, use company_name
292
+ */
255
293
  companyName?: string;
256
294
 
295
+ /**
296
+ * Custom key-value pairs. Merged with existing variables (not replaced).
297
+ */
298
+ custom_variables?: { [key: string]: string };
299
+
300
+ /**
301
+ * Contact's first name (preferred)
302
+ */
303
+ first_name?: string;
304
+
305
+ /**
306
+ * @deprecated Deprecated, use first_name
307
+ */
257
308
  firstName?: string;
258
309
 
310
+ /**
311
+ * Contact's last name (preferred)
312
+ */
313
+ last_name?: string;
314
+
315
+ /**
316
+ * @deprecated Deprecated, use last_name
317
+ */
259
318
  lastName?: string;
260
319
 
320
+ /**
321
+ * Associated Sendblue phone number (preferred)
322
+ */
323
+ sendblue_number?: string;
324
+
325
+ /**
326
+ * @deprecated Deprecated, use sendblue_number
327
+ */
261
328
  sendblueNumber?: string;
262
329
 
263
330
  tags?: Array<string>;
264
331
  }
265
332
 
333
+ export interface ContactListParams {
334
+ /**
335
+ * Filter by contact ID
336
+ */
337
+ cid?: string;
338
+
339
+ /**
340
+ * Maximum number of contacts to return
341
+ */
342
+ limit?: number;
343
+
344
+ /**
345
+ * Number of contacts to skip
346
+ */
347
+ offset?: number;
348
+
349
+ /**
350
+ * Field to sort by
351
+ */
352
+ order_by?: string;
353
+
354
+ /**
355
+ * Sort direction
356
+ */
357
+ order_direction?: 'asc' | 'desc';
358
+
359
+ /**
360
+ * Filter by phone number
361
+ */
362
+ phone_number?: string;
363
+ }
364
+
266
365
  export interface ContactVerifyParams {
267
366
  /**
268
367
  * Phone number to verify
@@ -284,6 +383,7 @@ export declare namespace Contacts {
284
383
  type ContactVerifyResponse as ContactVerifyResponse,
285
384
  type ContactCreateParams as ContactCreateParams,
286
385
  type ContactUpdateParams as ContactUpdateParams,
386
+ type ContactListParams as ContactListParams,
287
387
  type ContactVerifyParams as ContactVerifyParams,
288
388
  };
289
389
 
@@ -19,5 +19,6 @@ export {
19
19
  type ContactVerifyResponse,
20
20
  type ContactCreateParams,
21
21
  type ContactUpdateParams,
22
+ type ContactListParams,
22
23
  type ContactVerifyParams,
23
24
  } from './contacts';
@@ -5,6 +5,9 @@ import * as MessagesAPI from './messages';
5
5
  import { APIPromise } from '../core/api-promise';
6
6
  import { RequestOptions } from '../internal/request-options';
7
7
 
8
+ /**
9
+ * Operations for group messaging (beta)
10
+ */
8
11
  export class Groups extends APIResource {
9
12
  /**
10
13
  * Add or manage participants in a group chat (beta feature)
@@ -12,6 +12,7 @@ export {
12
12
  type ContactVerifyResponse,
13
13
  type ContactCreateParams,
14
14
  type ContactUpdateParams,
15
+ type ContactListParams,
15
16
  type ContactVerifyParams,
16
17
  } from './contacts/contacts';
17
18
  export {
@@ -4,6 +4,9 @@ import { APIResource } from '../core/resource';
4
4
  import { APIPromise } from '../core/api-promise';
5
5
  import { RequestOptions } from '../internal/request-options';
6
6
 
7
+ /**
8
+ * Operations for looking up service availability for phone numbers
9
+ */
7
10
  export class Lookups extends APIResource {
8
11
  /**
9
12
  * Determine if a phone number supports iMessage or SMS. Useful for checking if a
@@ -4,6 +4,9 @@ import { APIResource } from '../core/resource';
4
4
  import { APIPromise } from '../core/api-promise';
5
5
  import { RequestOptions } from '../internal/request-options';
6
6
 
7
+ /**
8
+ * Operations for uploading and managing media files
9
+ */
7
10
  export class MediaObjects extends APIResource {
8
11
  /**
9
12
  * Upload a media file to Sendblue's CDN for use in messages
@@ -5,6 +5,9 @@ import { APIPromise } from '../core/api-promise';
5
5
  import { RequestOptions } from '../internal/request-options';
6
6
  import { path } from '../internal/utils/path';
7
7
 
8
+ /**
9
+ * Operations for sending and managing messages
10
+ */
8
11
  export class Messages extends APIResource {
9
12
  /**
10
13
  * Retrieve details of a specific message by its ID
@@ -24,6 +27,22 @@ export class Messages extends APIResource {
24
27
  * Retrieve a list of messages for the authenticated account with comprehensive
25
28
  * filtering capabilities. Rate limited to 100 requests per 10 seconds per account.
26
29
  *
30
+ * ## Common Use Cases
31
+ *
32
+ * **Polling for inbound messages (no webhooks):**
33
+ *
34
+ * ```
35
+ * GET /api/v2/messages?is_outbound=false&sendblue_number=+16292925296&order_by=createdAt&order_direction=desc&limit=50
36
+ * ```
37
+ *
38
+ * Track processed message IDs to avoid duplicates.
39
+ *
40
+ * **Get conversation with a specific contact:**
41
+ *
42
+ * ```
43
+ * GET /api/v2/messages?number=+15551234567&order_by=createdAt&order_direction=desc
44
+ * ```
45
+ *
27
46
  * @example
28
47
  * ```ts
29
48
  * const messages = await client.messages.list();
@@ -129,7 +148,7 @@ export interface MessageContent {
129
148
  | 'loud'
130
149
  | 'slam';
131
150
 
132
- status?: 'QUEUED' | 'SENT' | 'DELIVERED' | 'READ' | 'ERROR' | 'RECEIVED';
151
+ status?: 'QUEUED' | 'SENT' | 'DELIVERED' | 'ERROR' | 'RECEIVED';
133
152
 
134
153
  /**
135
154
  * Recipient phone number
@@ -211,7 +230,7 @@ export interface MessageResponse {
211
230
  | 'loud'
212
231
  | 'slam';
213
232
 
214
- status?: 'QUEUED' | 'SENT' | 'DELIVERED' | 'READ' | 'ERROR';
233
+ status?: 'QUEUED' | 'SENT' | 'DELIVERED' | 'ERROR';
215
234
  }
216
235
 
217
236
  export interface MessageRetrieveResponse {
@@ -337,7 +356,10 @@ export namespace MessageRetrieveResponse {
337
356
  */
338
357
  sendblue_number?: string | null;
339
358
 
340
- service?: 'iMessage' | 'SMS';
359
+ /**
360
+ * The messaging service used
361
+ */
362
+ service?: 'iMessage' | 'SMS' | 'RCS';
341
363
 
342
364
  status?:
343
365
  | 'REGISTERED'
@@ -488,7 +510,10 @@ export namespace MessageListResponse {
488
510
  */
489
511
  sendblue_number?: string | null;
490
512
 
491
- service?: 'iMessage' | 'SMS';
513
+ /**
514
+ * The messaging service used
515
+ */
516
+ service?: 'iMessage' | 'SMS' | 'RCS';
492
517
 
493
518
  status?:
494
519
  | 'REGISTERED'
@@ -563,7 +588,14 @@ export interface MessageListParams {
563
588
  group_id?: string;
564
589
 
565
590
  /**
566
- * Filter by message direction
591
+ * Filter by message direction. Use `false` to get inbound messages (messages sent
592
+ * TO your Sendblue number).
593
+ *
594
+ * **To get inbound messages for polling:** Use `is_outbound=false` combined with
595
+ * `sendblue_number` or `to_number` set to your Sendblue phone number.
596
+ *
597
+ * Note: Do NOT use `message_type=inbound` - that parameter only accepts `message`
598
+ * or `group` values.
567
599
  */
568
600
  is_outbound?: 'true' | 'false';
569
601
 
@@ -573,10 +605,18 @@ export interface MessageListParams {
573
605
  limit?: number;
574
606
 
575
607
  /**
576
- * Filter by message type
608
+ * Filter by message type (1:1 vs group chat). Only accepts `message` or `group`.
609
+ *
610
+ * **Common mistake:** This is NOT for filtering inbound vs outbound messages. Use
611
+ * `is_outbound` parameter instead.
577
612
  */
578
613
  message_type?: 'message' | 'group';
579
614
 
615
+ /**
616
+ * Filter by any phone number (from or to)
617
+ */
618
+ number?: string;
619
+
580
620
  /**
581
621
  * Number of messages to skip
582
622
  */
@@ -592,6 +632,11 @@ export interface MessageListParams {
592
632
  */
593
633
  order_direction?: 'asc' | 'desc';
594
634
 
635
+ /**
636
+ * Filter by Sendblue phone number
637
+ */
638
+ sendblue_number?: string;
639
+
595
640
  /**
596
641
  * Filter messages sent after this date (ISO 8601 format)
597
642
  */
@@ -605,7 +650,7 @@ export interface MessageListParams {
605
650
  /**
606
651
  * Filter by service type
607
652
  */
608
- service?: 'iMessage' | 'SMS';
653
+ service?: 'iMessage' | 'SMS' | 'RCS';
609
654
 
610
655
  /**
611
656
  * Filter by message status