@trycourier/courier 6.4.0 → 6.4.2

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 (133) hide show
  1. package/Client.d.ts +14 -48
  2. package/Client.js +20 -49
  3. package/README.md +113 -808
  4. package/api/client/requests/SendMessageRequest.d.ts +12 -47
  5. package/api/resources/audiences/client/Client.d.ts +10 -5
  6. package/api/resources/audiences/client/Client.js +45 -15
  7. package/api/resources/auditEvents/client/Client.d.ts +4 -2
  8. package/api/resources/auditEvents/client/Client.js +17 -5
  9. package/api/resources/authTokens/client/Client.d.ts +2 -1
  10. package/api/resources/authTokens/client/Client.js +8 -2
  11. package/api/resources/automations/client/Client.d.ts +4 -2
  12. package/api/resources/automations/client/Client.js +16 -4
  13. package/api/resources/brands/client/Client.d.ts +10 -5
  14. package/api/resources/brands/client/Client.js +45 -15
  15. package/api/resources/bulk/client/Client.d.ts +10 -5
  16. package/api/resources/bulk/client/Client.js +45 -15
  17. package/api/resources/commons/errors/AlreadyExistsError.d.ts +2 -1
  18. package/api/resources/commons/errors/AlreadyExistsError.js +2 -1
  19. package/api/resources/commons/errors/BadRequestError.d.ts +2 -1
  20. package/api/resources/commons/errors/BadRequestError.js +2 -1
  21. package/api/resources/commons/errors/ConflictError.d.ts +2 -1
  22. package/api/resources/commons/errors/ConflictError.js +2 -1
  23. package/api/resources/commons/errors/MessageNotFoundError.d.ts +2 -1
  24. package/api/resources/commons/errors/MessageNotFoundError.js +2 -1
  25. package/api/resources/commons/errors/NotFoundError.d.ts +2 -1
  26. package/api/resources/commons/errors/NotFoundError.js +2 -1
  27. package/api/resources/commons/errors/PaymentRequiredError.d.ts +2 -1
  28. package/api/resources/commons/errors/PaymentRequiredError.js +2 -1
  29. package/api/resources/inbound/client/Client.d.ts +2 -1
  30. package/api/resources/inbound/client/Client.js +10 -4
  31. package/api/resources/lists/client/Client.d.ts +20 -10
  32. package/api/resources/lists/client/Client.js +89 -29
  33. package/api/resources/messages/client/Client.d.ts +12 -6
  34. package/api/resources/messages/client/Client.js +56 -20
  35. package/api/resources/notifications/client/Client.d.ts +12 -6
  36. package/api/resources/notifications/client/Client.js +58 -13
  37. package/api/resources/profiles/client/Client.d.ts +16 -8
  38. package/api/resources/profiles/client/Client.js +75 -24
  39. package/api/resources/templates/client/Client.d.ts +2 -1
  40. package/api/resources/templates/client/Client.js +9 -3
  41. package/api/resources/tenants/client/Client.d.ts +14 -7
  42. package/api/resources/tenants/client/Client.js +61 -19
  43. package/api/resources/translations/client/Client.d.ts +4 -2
  44. package/api/resources/translations/client/Client.js +18 -6
  45. package/api/resources/users/resources/preferences/client/Client.d.ts +6 -3
  46. package/api/resources/users/resources/preferences/client/Client.js +38 -11
  47. package/api/resources/users/resources/tenants/client/Client.d.ts +10 -5
  48. package/api/resources/users/resources/tenants/client/Client.js +45 -12
  49. package/api/resources/users/resources/tokens/client/Client.d.ts +12 -6
  50. package/api/resources/users/resources/tokens/client/Client.js +53 -17
  51. package/core/fetcher/APIResponse.d.ts +10 -0
  52. package/core/fetcher/Fetcher.js +7 -0
  53. package/core/fetcher/Headers.d.ts +2 -0
  54. package/core/fetcher/Headers.js +84 -0
  55. package/core/fetcher/HttpResponsePromise.d.ts +58 -0
  56. package/core/fetcher/HttpResponsePromise.js +103 -0
  57. package/core/fetcher/RawResponse.d.ts +29 -0
  58. package/core/fetcher/RawResponse.js +44 -0
  59. package/core/fetcher/index.d.ts +3 -0
  60. package/core/fetcher/index.js +7 -1
  61. package/core/index.d.ts +1 -1
  62. package/core/index.js +1 -1
  63. package/dist/Client.d.ts +14 -48
  64. package/dist/Client.js +20 -49
  65. package/dist/api/client/requests/SendMessageRequest.d.ts +12 -47
  66. package/dist/api/resources/audiences/client/Client.d.ts +10 -5
  67. package/dist/api/resources/audiences/client/Client.js +45 -15
  68. package/dist/api/resources/auditEvents/client/Client.d.ts +4 -2
  69. package/dist/api/resources/auditEvents/client/Client.js +17 -5
  70. package/dist/api/resources/authTokens/client/Client.d.ts +2 -1
  71. package/dist/api/resources/authTokens/client/Client.js +8 -2
  72. package/dist/api/resources/automations/client/Client.d.ts +4 -2
  73. package/dist/api/resources/automations/client/Client.js +16 -4
  74. package/dist/api/resources/brands/client/Client.d.ts +10 -5
  75. package/dist/api/resources/brands/client/Client.js +45 -15
  76. package/dist/api/resources/bulk/client/Client.d.ts +10 -5
  77. package/dist/api/resources/bulk/client/Client.js +45 -15
  78. package/dist/api/resources/commons/errors/AlreadyExistsError.d.ts +2 -1
  79. package/dist/api/resources/commons/errors/AlreadyExistsError.js +2 -1
  80. package/dist/api/resources/commons/errors/BadRequestError.d.ts +2 -1
  81. package/dist/api/resources/commons/errors/BadRequestError.js +2 -1
  82. package/dist/api/resources/commons/errors/ConflictError.d.ts +2 -1
  83. package/dist/api/resources/commons/errors/ConflictError.js +2 -1
  84. package/dist/api/resources/commons/errors/MessageNotFoundError.d.ts +2 -1
  85. package/dist/api/resources/commons/errors/MessageNotFoundError.js +2 -1
  86. package/dist/api/resources/commons/errors/NotFoundError.d.ts +2 -1
  87. package/dist/api/resources/commons/errors/NotFoundError.js +2 -1
  88. package/dist/api/resources/commons/errors/PaymentRequiredError.d.ts +2 -1
  89. package/dist/api/resources/commons/errors/PaymentRequiredError.js +2 -1
  90. package/dist/api/resources/inbound/client/Client.d.ts +2 -1
  91. package/dist/api/resources/inbound/client/Client.js +10 -4
  92. package/dist/api/resources/lists/client/Client.d.ts +20 -10
  93. package/dist/api/resources/lists/client/Client.js +89 -29
  94. package/dist/api/resources/messages/client/Client.d.ts +12 -6
  95. package/dist/api/resources/messages/client/Client.js +56 -20
  96. package/dist/api/resources/notifications/client/Client.d.ts +12 -6
  97. package/dist/api/resources/notifications/client/Client.js +58 -13
  98. package/dist/api/resources/profiles/client/Client.d.ts +16 -8
  99. package/dist/api/resources/profiles/client/Client.js +75 -24
  100. package/dist/api/resources/templates/client/Client.d.ts +2 -1
  101. package/dist/api/resources/templates/client/Client.js +9 -3
  102. package/dist/api/resources/tenants/client/Client.d.ts +14 -7
  103. package/dist/api/resources/tenants/client/Client.js +61 -19
  104. package/dist/api/resources/translations/client/Client.d.ts +4 -2
  105. package/dist/api/resources/translations/client/Client.js +18 -6
  106. package/dist/api/resources/users/resources/preferences/client/Client.d.ts +6 -3
  107. package/dist/api/resources/users/resources/preferences/client/Client.js +38 -11
  108. package/dist/api/resources/users/resources/tenants/client/Client.d.ts +10 -5
  109. package/dist/api/resources/users/resources/tenants/client/Client.js +45 -12
  110. package/dist/api/resources/users/resources/tokens/client/Client.d.ts +12 -6
  111. package/dist/api/resources/users/resources/tokens/client/Client.js +53 -17
  112. package/dist/core/fetcher/APIResponse.d.ts +10 -0
  113. package/dist/core/fetcher/Fetcher.js +7 -0
  114. package/dist/core/fetcher/Headers.d.ts +2 -0
  115. package/dist/core/fetcher/Headers.js +84 -0
  116. package/dist/core/fetcher/HttpResponsePromise.d.ts +58 -0
  117. package/dist/core/fetcher/HttpResponsePromise.js +103 -0
  118. package/dist/core/fetcher/RawResponse.d.ts +29 -0
  119. package/dist/core/fetcher/RawResponse.js +44 -0
  120. package/dist/core/fetcher/index.d.ts +3 -0
  121. package/dist/core/fetcher/index.js +7 -1
  122. package/dist/core/index.d.ts +1 -1
  123. package/dist/core/index.js +1 -1
  124. package/dist/errors/CourierError.d.ts +4 -1
  125. package/dist/errors/CourierError.js +4 -7
  126. package/dist/version.d.ts +1 -1
  127. package/dist/version.js +1 -1
  128. package/errors/CourierError.d.ts +4 -1
  129. package/errors/CourierError.js +4 -7
  130. package/package.json +3 -2
  131. package/reference.md +12 -50
  132. package/version.d.ts +1 -1
  133. package/version.js +1 -1
package/README.md CHANGED
@@ -1,880 +1,185 @@
1
- [![Courier: Your Complete Communication Stack](https://marketing-assets-public.s3.us-west-1.amazonaws.com/github_nodejs.png)](https://courier.com)
1
+ # Courier TypeScript Library
2
2
 
3
+ [![fern shield](https://img.shields.io/badge/%F0%9F%8C%BF-Built%20with%20Fern-brightgreen)](https://buildwithfern.com?utm_source=github&utm_medium=github&utm_campaign=readme&utm_source=https%3A%2F%2Fgithub.com%2Ftrycourier%2Fcourier-node)
3
4
  [![npm shield](https://img.shields.io/npm/v/@trycourier/courier)](https://www.npmjs.com/package/@trycourier/courier)
4
- [![fern shield](https://img.shields.io/badge/%F0%9F%8C%BF-SDK%20generated%20by%20Fern-brightgreen)](https://buildwithfern.com/?utm_source=trycourier/courier-node/readme)
5
5
 
6
- This is the official node.js module for sending notifications with node.js with the [Courier](https://courier.com) REST API.
6
+ The Courier TypeScript library provides convenient access to the Courier API from TypeScript.
7
7
 
8
- [Courier docs](https://docs.courier.com/docs) • [3 Different Ways To Send Emails With Node.js](https://www.courier.com/blog/how-to-send-emails-with-node-js?utm_campaign=General-Content-Distribution&utm_source=github&utm_medium=node-sdk)
8
+ ## Documentation
9
9
 
10
- ## Installation (via [npm](https://www.npmjs.com/package/@trycourier/courier))
10
+ API reference documentation is available [here](https://www.courier.com/docs).
11
11
 
12
- ```bash
13
- npm install @trycourier/courier
14
- ```
15
-
16
- ## Requirements
17
-
18
- You will need to get a Courier API key to get started. You can sign up and create one for free at [courier.com](https://courier.com).
19
-
20
- ## Upgrade Guides
12
+ ## Installation
21
13
 
22
- ### v5 to v6
23
-
24
- v6 of our SDK is automatically generated by [Fern](https://buildwithfern.com/). v6 comes
25
- with several improvements that we describe below:
14
+ ```sh
15
+ npm i -s @trycourier/courier
16
+ ```
26
17
 
27
- - **Resource-scoped SDK methods**: Endpoints are scoped under their resource. For
28
- example, instead of `courier.deleteBrands` the SDK now reads `courier.brands.delete(...)`
29
- - **Docs on Hover**: All endpoint and parameter level documentation that you see
30
- on our docs website is now embedded directly within the SDKs.
31
- - **Retries with exponential backoff**: The SDK will automatically retry failures with
32
- exponential backoff. You can configure the retries by setting `maxRetries`.
33
- ```typescript
34
- const response = courier.send(..., {
35
- maxReries: 0 // set to 0 if you want to disable retries
36
- })
37
- ```
38
- - **Configurable Timeouts**: The SDK defaults to a 60 second timeout. You can also
39
- configure this value per-request.
40
- ```typescript
41
- const response = courier.send(..., {
42
- timeoutInSeconds: 45 // set to 45 seconds for this particular request
43
- })
44
- ```
45
- - **Support for multiple runtimes**: The SDK uses global fetch when available, otherwise
46
- defaults to node-fetch. This means you can use Courier in multiple runtimes; Node.js,
47
- Vercel, and Cloudflare Workers.
18
+ ## Reference
48
19
 
49
- ### v3 to v4
20
+ A full reference for this library is available [here](./reference.md).
50
21
 
51
- v4 uses native fetch client to make requests or falls back to a polyfill if the client doesn't exist in the environment it's running in. Check [Error Handling](#Error-Handling) out.
22
+ ## Usage
52
23
 
53
- ## Getting Started
24
+ Instantiate and use the client with the following:
54
25
 
55
- ```javascript
26
+ ```typescript
56
27
  import { CourierClient } from "@trycourier/courier";
57
28
 
58
- const courier = new CourierClient({ authorizationToken: "<AUTH_TOKEN>" }); // get from the Courier UI
59
-
60
- // Example: send a basic message to an email recipient
61
- const { requestId } = await courier.send({
62
- message: {
63
- to: {
64
- data: {
65
- name: "Marty",
66
- },
67
- email: "marty_mcfly@email.com",
68
- },
69
- content: {
70
- title: "Back to the Future",
71
- body: "Oh my {{name}}, we need 1.21 Gigawatts!",
72
- },
73
- routing: {
74
- method: "single",
75
- channels: ["email"],
76
- },
77
- },
78
- });
79
-
80
- // Example: send a basic message to an sms recipient
81
- const { requestId } = await courier.send({
82
- message: {
83
- to: {
84
- data: {
85
- name: "Jenny",
86
- },
87
- phone_number: "8675309",
88
- },
89
- content: {
90
- title: "Back to the Future",
91
- body: "Oh my {{name}}, we need 1.21 Gigawatts!",
92
- },
93
- routing: {
94
- method: "single",
95
- channels: ["sms"],
96
- },
97
- },
98
- });
99
-
100
- // Example: send a message to various recipients
101
- const { requestId } = await courier.send({
102
- message: {
103
- to: [
104
- {
105
- user_id: "<USER_ID>", // usually your system's User ID associated to a Courier profile
106
- email: "test@email.com",
107
- data: {
108
- name: "some user's name",
29
+ const client = new CourierClient({ authorizationToken: "YOUR_AUTHORIZATION_TOKEN" });
30
+ await client.send({
31
+ message: {
32
+ to: {
33
+ email: "email@example.com",
109
34
  },
110
- },
111
- {
112
- email: "marty@email.com",
113
- data: {
114
- name: "Marty",
35
+ content: {
36
+ title: "Welcome!",
37
+ body: "Thanks for signing up, {{name}}",
115
38
  },
116
- },
117
- {
118
- email: "doc_brown@email.com",
119
39
  data: {
120
- name: "Doc",
40
+ name: "Peter Parker",
121
41
  },
122
- },
123
- {
124
- phone_number: "8675309",
125
- data: {
126
- name: "Jenny",
42
+ routing: {
43
+ method: "single",
44
+ channels: ["email"],
127
45
  },
128
- },
129
- ],
130
- content: {
131
- title: "Back to the Future",
132
- body: "Oh my {{name}}, we need 1.21 Gigawatts!",
133
- },
134
- routing: {
135
- method: "all",
136
- channels: ["sms", "email"],
137
46
  },
138
- },
139
- });
140
-
141
- // Example: send a message supporting email & SMS
142
- const { requestId } = await courier.send({
143
- message: {
144
- template: "<TEMPLATE_OR_EVENT_ID>", // get from the Courier UI
145
- to: {
146
- user_Id: "<USER_ID>", // usually your system's User ID
147
- email: "example@example.com",
148
- phone_number: "555-228-3890",
149
- },
150
- data: {}, // optional variables for merging into templates
151
- },
152
- });
153
-
154
- // Example: send a message to a list
155
- const { requestId } = await courier.send({
156
- message: {
157
- template: "<TEMPLATE_OR_EVENT_ID>", // get from the Courier UI
158
- to: {
159
- list_id: "<LIST_ID>", // e.g. your Courier List Id
160
- },
161
- data: {}, // optional variables for merging into templates
162
- },
163
- });
164
-
165
- // Example: send a message to a pattern
166
- const { requestId } = await courier.send({
167
- message: {
168
- template: "<TEMPLATE_OR_EVENT_ID>", // get from the Courier UI
169
- to: {
170
- list_pattern: "<PATTERN>", // e.g. example.list.*
171
- },
172
- data: {}, // optional variables for merging into templates
173
- },
174
- });
175
-
176
- // Example: send a message to a list, pattern and user
177
- const { requestId } = await courier.send({
178
- message: {
179
- content: {
180
- title: "Hello",
181
- body: "Good morning!"
182
- },
183
- to: [
184
- {
185
- list_pattern: "<PATTERN>", // e.g. example.list.*
186
- },
187
- {
188
- list_id: "<LIST_ID>", // e.g. your Courier List Id
189
- },
190
- {
191
- email: "test@email.com"
192
- }
193
- ]
194
- },
195
- routing: {
196
- method: "single",
197
- channels: ["email"],
198
- },
199
- });
200
-
201
- // Example: send a basic message that expires after the specified timeout
202
- const { requestId } = await courier.send({
203
- message: {
204
- to: {
205
- data: {
206
- name: "Marty",
207
- },
208
- email: "marty_mcfly@email.com",
209
- },
210
- content: {
211
- title: "Back to the Future",
212
- body: "Oh my {{name}}, we need 1.21 Gigawatts!",
213
- },
214
- routing: {
215
- method: "single",
216
- channels: ["email"],
217
- },
218
- timeout: {
219
- message: 3600000 // 1 hour in milliseconds
220
- },
221
- },
222
- });
223
-
224
- // Example: send a basic message with a trace id
225
- const { requestId } = await courier.send({
226
- message: {
227
- to: {
228
- data: {
229
- name: "Marty",
230
- },
231
- email: "marty_mcfly@email.com",
232
- },
233
- content: {
234
- title: "Back to the Future",
235
- body: "Oh my {{name}}, we need 1.21 Gigawatts!",
236
- },
237
- routing: {
238
- method: "single",
239
- channels: ["email"],
240
- },
241
- metadata: {
242
- trace_id: "ravenclaw-for-the-win"
243
- },
244
- },
245
47
  });
246
48
  ```
247
49
 
248
- ## Environment Variables
50
+ ## Request And Response Types
249
51
 
250
- `courier-node` supports credential storage in environment variables. If no `authorizationToken` is provided when instantiating the Courier client (e.g., `const courier = CourierClient();`), the value in the `COURIER_AUTH_TOKEN` env var will be used.
52
+ The SDK exports all request and response types as TypeScript interfaces. Simply import them with the
53
+ following namespace:
251
54
 
252
- If you need to use a base url other than the default https://api.courier.com, you can set it using the `COURIER_BASE_URL` env var.
55
+ ```typescript
56
+ import { Courier } from "@trycourier/courier";
253
57
 
254
- ## Advanced Usage
58
+ const request: Courier.SendMessageRequest = {
59
+ ...
60
+ };
61
+ ```
255
62
 
256
- ```javascript
257
- const { CourierClient } = require("@trycourier/courier");
63
+ ## Exception Handling
258
64
 
259
- const courier = CourierClient({ authorizationToken: "<AUTH_TOKEN>" });
65
+ When the API returns a non-success status code (4xx or 5xx response), a subclass of the following error
66
+ will be thrown.
260
67
 
261
- async function run() {
262
- // Example: send a message
263
- const { requestId } = await courier.send({
264
- message: {
265
- template: "<TEMPLATE_OR_EVENT_ID>",
266
- to: {
267
- // optional
268
- user_id: "<RECIPIENT_ID>",
269
- },
270
- data: {}, // optional
271
- brand_id: "<BRAND_ID>", //optional
272
- channels: {}, // optional
273
- providers: {}, // optional
274
- },
275
- });
276
- console.log(requestId);
68
+ ```typescript
69
+ import { CourierError } from "@trycourier/courier";
277
70
 
278
- // Example: send message with utm metadata
279
- const { requestId } = await courier.send({
280
- message: {
281
- template: "<TEMPLATE_OR_EVENT_ID>",
282
- to: {...},
283
- routing: {
284
- method: "single",
285
- channels: ["email"],
286
- },
287
- channels: {
288
- email: {
289
- routing_method: "all",
290
- providers: ["sendgrid", "sns"],
291
- metadata: {
292
- utm: {
293
- medium: "f",
294
- campaign: "g",
295
- },
296
- },
297
- },
298
- },
299
- providers: {
300
- sns: {
301
- metadata: {
302
- utm: {
303
- medium: "h",
304
- },
305
- },
306
- },
307
- }, // optional
308
- metadata: {
309
- utm: {
310
- source: "a",
311
- medium: "b",
312
- campaign: "c",
313
- },
314
- },
315
- timeout: {
316
- message: 300000,
317
- channel: {
318
- email: 1000 // 1 second
319
- }
320
- }
321
- },
322
- });
323
-
324
- /**
325
- * If the template or content contains any action blocks, the hyperlinks will be augmented with utm compliant query parameters.
326
- *
327
- * The resulting link of an action block sent through sendgrid would be:
328
- * www.example.com?utm_source=a&utm_medium=f&utm_campaign=g
329
- *
330
- * While the resulting link of an action block sent through sns would be:
331
- * www.example.com?utm_source=a&utm_medium=h&utm_campaign=g
332
- *
333
- * Notice that provider metadata supersedes channel metadata and channel metadata supersedes message metadata
334
- *
335
- **/
336
-
337
- /**
338
- * If the message includes a timeout property we will start timing out messages after the first attempt.
339
- * We are able to timeout complete channels or specific providers.
340
- **/
341
-
342
- // Example: get a message status
343
- const messageStatus = await courier.messages.get(requestId);
344
- console.log(messageStatus);
345
-
346
- // Example: get a message history
347
- const { results } = await courier.messages.getHistory(requestId);
348
- console.log(results);
349
-
350
- // Example: get a message output
351
- const { results } = await courier.messages.getContent(requestId);
352
- console.log(results);
353
-
354
- // Example: get all messages
355
- const { paging, results } = await courier.messages.list();
356
- console.log(results);
357
-
358
- // Example: replace a recipient's profile
359
- const { status: replaceStatus } = await courier.profiles.replace(
360
- "<RECIPIENT_ID>",
361
- {
362
- profile: {
363
- email: "example@example.com",
364
- },
365
- }
366
- );
367
- console.log(replaceStatus);
368
-
369
- // Example: merge into a recipient's profile
370
- const { status: mergeStatus } = await courier.profiles.create(
371
- "<RECIPIENT_ID>",
372
- {
373
- profile: {
374
- sms: "555-555-5555",
375
- },
376
- }
377
- );
378
- console.log(mergeStatus);
379
-
380
- // Example: get a recipient's profile
381
- const { profile } = await courier.profiles.get("<RECIPIENT_ID>");
382
- console.log(profile);
383
-
384
- // Example: get all brands
385
- const { paging, results } = await courier.brands.list({
386
- cursor: "<CURSOR>", // optional
387
- });
388
- console.log(results);
389
-
390
- // Example: get a specific brand
391
- const brand = await courier.brands.get("<BRAND_ID>");
392
- console.log(brand);
393
-
394
- // Example: create a brand
395
- const newBrand = await courier.brands.create({
396
- name: "My Brand",
397
- settings: {
398
- colors: {
399
- primary: "#0000FF",
400
- secondary: "#FF0000",
401
- tertiary: "#00FF00",
402
- },
403
- },
404
- });
405
- console.log(newBrand);
406
-
407
- // Example: replace a brand
408
- const replacedBrand = await courier.brands.replace("<BRAND_ID>", {
409
- name: "My New Brand",
410
- settings: {
411
- colors: {
412
- primary: "#FF0000",
413
- secondary: "#00FF00",
414
- tertiary: "#0000FF",
415
- },
416
- },
417
- });
418
- console.log(replacedBrand);
419
-
420
- // Example: delete a brand
421
- await courier.brands.delete("<BRAND_ID>");
422
-
423
- // Example: get all lists
424
- const { paging, items } = await courier.lists.list({
425
- cursor: "<CURSOR>", // optional
426
- });
427
- console.log(items);
428
-
429
- // Example: get a specific list
430
- const list = await courier.lists.get("<LIST_ID>");
431
- console.log(list);
432
-
433
- // Example: create or replace a list
434
- const replacedList = await courier.lists.update("<LIST_ID>", {
435
- name: "My New List",
436
- });
437
- console.log(replacedList);
438
-
439
- // Example: delete a list
440
- await courier.lists.delete("<LIST_ID>");
441
-
442
- // Example: restore a list
443
- await courier.lists.restore("<LIST_ID>");
444
-
445
- // Example: get a list's subscribers
446
- const { paging, items } = await courier.lists.getSubscribers("<LIST_ID>");
447
- console.log(items);
448
-
449
- // Example: replace many recipients to a new or existing list
450
- await courier.lists.updateSubscribers("<LIST_ID>", [
451
- { recipientId: "RECIPIENT_ID_1" },
452
- { recipientId: "RECIPIENT_ID_2" },
453
- ]);
454
-
455
- // Example: subscribe single recipient to a new or existing list
456
- await courier.lists.subscribe("<LIST_ID>", "<RECIPIENT_ID>");
457
- console.log(recipient);
458
-
459
- // Example: unsubscribe recipient from list
460
- await courier.lists.unsubscribe("<LIST_ID>", "<RECIPIENT_ID>");
461
-
462
- // Example: get a recipient's subscribed lists
463
- const { paging, items } = await courier.lists.getSubscribers(
464
- "<RECIPIENT_ID>"
465
- );
466
- console.log(items);
467
-
468
- // Example: Automation Ad-Hoc Invoke
469
- const { runId } = await courier.automations.invokeAdHocAutomation({
470
- automation: {
471
- cancelation_token: "I_AM_TOKEN",
472
- steps: [
473
- {
474
- action: "send",
475
- },
476
- ],
477
- },
478
- brand: "BRAND_ID",
479
- data: {
480
- example: "EXAMPLE_DATA",
481
- },
482
- profile: {
483
- email: "foo@bar.com",
484
- },
485
- recipient: "RECIPIENT_ID",
486
- template: "TEMPLATE_NAME_OR_ID",
487
- });
488
- console.log(runId);
489
-
490
- // Example: Automation Invoke Template
491
- const { runId } = await courier.automations.invokeAutomationTemplate(
492
- "AUTOMATION_TEMPLATE_ID",
493
- {
494
- brand: "BRAND_ID",
495
- data: {
496
- example: "EXAMPLE_DATA",
497
- },
498
- profile: {
499
- email: "foo@bar.com",
500
- },
501
- recipient: "RECIPIENT_ID",
502
- template: "TEMPLATE_NAME_OR_ID",
503
- }
504
- );
505
- console.log(runId);
506
-
507
- // Example: List notifications
508
- const { paging, results } = await courier.notifications.list();
509
- console.log(results);
510
-
511
- // Example: Get notification content
512
- const { blocks, channels } = await courier.notifications.getContent(
513
- "notification1"
514
- );
515
- console.log(blocks);
516
- console.log(channels);
517
-
518
- // Example: Get notification draft content
519
- const { blocks, channels } = await courier.notifications.getDraftContent(
520
- "notification1"
521
- );
522
- console.log(blocks);
523
- console.log(channels);
524
-
525
- // Example: Post notification variations
526
- await courier.notifications.updateVariations("notification1", {
527
- blocks: [
528
- {
529
- id: "block_1d4c32e0-bca8-43f6-b5d5-8c043199bce6",
530
- type: "text",
531
- locales: {
532
- fr_FR: "block fr 1",
533
- },
534
- },
535
- {
536
- id: "block_6d50a6e3-ecc3-4815-bf51-0202c6bf54e2",
537
- type: "text",
538
- locales: {
539
- fr_FR: "block fr 2",
540
- },
541
- },
542
- ],
543
- channels: [
544
- {
545
- id: "channel_1ba46024-f156-4ed7-893b-cb1cdcfbd36e",
546
- type: "email",
547
- locales: {
548
- fr_FR: {
549
- subject: "French Subject",
550
- },
551
- },
552
- },
553
- {
554
- id: "channel_2c2aad1c-30f0-4a55-8d8f-d213f32147bc",
555
- type: "push",
556
- locales: {
557
- fr_FR: {
558
- title: "French Title",
559
- },
560
- },
561
- },
562
- ],
563
- });
564
-
565
- // Example: Post notification draft variations
566
- await courier.notifications.updateDraftVariations("notification1", {
567
- blocks: [
568
- {
569
- id: "block_1d4c32e0-bca8-43f6-b5d5-8c043199bce6",
570
- type: "text",
571
- locales: {
572
- fr_FR: "block fr 1",
573
- },
574
- },
575
- {
576
- id: "block_6d50a6e3-ecc3-4815-bf51-0202c6bf54e2",
577
- type: "text",
578
- locales: {
579
- fr_FR: "block fr 2",
580
- },
581
- },
582
- ],
583
- channels: [
584
- {
585
- id: "channel_1ba46024-f156-4ed7-893b-cb1cdcfbd36e",
586
- type: "email",
587
- locales: {
588
- fr_FR: {
589
- subject: "French Subject",
590
- },
591
- },
592
- },
593
- {
594
- id: "channel_2c2aad1c-30f0-4a55-8d8f-d213f32147bc",
595
- type: "push",
596
- locales: {
597
- fr_FR: {
598
- title: "French Title",
599
- },
600
- },
601
- },
602
- ],
603
- });
604
-
605
- // Example: Get notification submission checks
606
- const { checks } = await courier.notifications.getSubmissionChecks(
607
- "notification1",
608
- "submission1"
609
- );
610
- console.log(checks);
611
-
612
- // Example: Put notification submission checks
613
- const { checks } = await courier.notifications.replaceSubmissionChecks(
614
- "notification1",
615
- "submission1",
616
- {
617
- checks: [
618
- {
619
- id: "check1",
620
- status: "RESOLVED",
621
- type: "custom",
622
- },
623
- ],
71
+ try {
72
+ await client.send(...);
73
+ } catch (err) {
74
+ if (err instanceof CourierError) {
75
+ console.log(err.statusCode);
76
+ console.log(err.message);
77
+ console.log(err.body);
78
+ console.log(err.rawResponse);
624
79
  }
625
- );
626
- console.log(checks);
627
-
628
- // Example: Cancel notification submission
629
- await courier.notifications.cancelSubmission("notification1", "submission1");
630
-
631
- // Bulk Processing
632
- // Example: create a job (API v1 semantics)
633
- const response = await courier.bulk.createJob({
634
- message: {
635
- event: "RR4NDQ7NZ24A8TKPWVBEDGE15E9A",
636
- },
637
- });
638
- console.log(response);
639
-
640
- // Example: create a job (API v2 semantics)
641
- const response = await courier.bulk.createJob({
642
- message: {
643
- message: {
644
- template: "RR4NDQ7NZ24A8TKPWVBEDGE15E9A",
645
- },
646
- },
647
- });
648
- console.log(response);
649
-
650
- // Example: get a job
651
- const response = await courier.bulk.getJob({
652
- jobId: "1-61efe386-6ff57552409e311b7a1f371f",
653
- });
654
- console.log(response);
655
-
656
- // Example: Ingest users in a job (API v1 semantics)
657
- const response = await courier.bulk.ingestUsers({
658
- jobId: "1-61efe386-6ff57552409e311b7a1f371f",
659
- users: [
660
- {
661
- profile: {
662
- email: "tejas@courier.com",
663
- },
664
- },
665
- ],
666
- });
667
- console.log(response);
668
-
669
- // Example: Ingest users in a job (API v2 semantics)
670
- const response = await courier.bulk.ingestUsers({
671
- jobId: "1-61efe386-6ff57552409e311b7a1f371f",
672
- users: [
673
- {
674
- to: {
675
- email: "tejas@courier.com",
676
- },
677
- },
678
- ],
679
- });
680
- console.log(response);
681
-
682
- // Example: Run a job
683
- await courier.bulk.runJob("1-61efe386-6ff57552409e311b7a1f371f");
684
-
685
- // Example: Get user details in a job
686
- const response = await courier.bulk.getUsers(
687
- "1-61efe386-6ff57552409e311b7a1f371f"
688
- );
689
- console.log(response);
690
80
  }
691
-
692
- run();
693
81
  ```
694
82
 
695
- ### Error Handling
696
-
697
- This package tries to use the native `fetch` client to make requests or falls back to a polyfill if the client doesn't exist in the environment it's running in.
698
-
699
- All network related promise rejections are not handled in any way. All successfully made requests that produce errors on the server side are resulting in promise rejections with custom `CourierError` error type.
700
-
701
- `CourierError` extends native `Error` interface with two extra properties:
702
-
703
- - `statusCode`: this is the status code of the response
704
- - `body`: this is the body of the response
83
+ ## Advanced
705
84
 
706
- ```javascript
707
- // Error handling example
708
- import { CourierError, CourierClient } from "@trycourier/courier";
85
+ ### Additional Headers
709
86
 
710
- const courier = new CourierClient();
87
+ If you would like to send additional headers as part of the request, use the `headers` request option.
711
88
 
712
- try {
713
- await courier.send(/* ... */);
714
- } catch (error) {
715
- if (error instanceof CourierError) {
716
- console.log("Failed to send with status code:", error.statusCode);
717
- console.log("The Courier body is:", error.body);
718
- console.log("The error message is:", error.message);
719
- } else {
720
- console.log(
721
- "There was a problem making that request. Make sure you are online."
722
- );
723
- }
724
- }
89
+ ```typescript
90
+ const response = await client.send(..., {
91
+ headers: {
92
+ 'X-Custom-Header': 'custom value'
93
+ }
94
+ });
725
95
  ```
726
96
 
727
- ### Idempotency
97
+ ### Retries
728
98
 
729
- For `POST` methods, you can supply an `idempotencyKey` in the config parameter to ensure the idempotency of the API Call. We recommend that you use a `V4 UUID` for the key. Keys are eligible to be removed from the system after they're at least 24 hours old, and a new request is generated if a key is reused after the original has been removed. For more info, see [Idempotent Requests](https://docs.courier.com/reference/idempotent-requests) in the Courier documentation.
99
+ The SDK is instrumented with automatic retries with exponential backoff. A request will be retried as long
100
+ as the request is deemed retryable and the number of retry attempts has not grown larger than the configured
101
+ retry limit (default: 2).
730
102
 
731
- ```javascript
732
- import { CourierClient } from "@trycourier/courier";
733
- import uuid4 from "uuid4";
734
-
735
- const courier = new CourierClient();
736
- const idempotencyKey = uuid4();
737
-
738
- async function run() {
739
- const { requestId } = await courier.send(
740
- {
741
- template: "<TEMPLATE_OR_EVENT_ID>",
742
- to: {
743
- user_id: "<USER_ID>",
744
- email: "example@example.com",
745
- phone_number: "555-867-5309",
746
- },
747
- data: {
748
- world: "JavaScript!",
749
- },
750
- },
751
- {
752
- idempotencyKey,
753
- }
754
- );
755
- console.log(requestId);
756
- }
103
+ A request is deemed retryable when any of the following HTTP status codes is returned:
757
104
 
758
- run();
759
- ```
760
-
761
- ### Audiences
105
+ - [408](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/408) (Timeout)
106
+ - [429](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/429) (Too Many Requests)
107
+ - [5XX](https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/500) (Internal Server Errors)
762
108
 
763
- Audiences APIs are used to create, get, update, and delete audiences. A Courier Audience is a dynamic group of users (created using Courier's Profile API) that matches a set of criteria. Audience is reactive to changes in the user's profile. As you change user profile using `profiles` API, the audience will be updated accordingly. You will not have to maintain a list of users in your audience. Courier takes care of that for you. If you have potentially large set of users, you first create an audience and then use the audience's id to retrieve the list of users. Once you satified with the calculated list of users, you can use the `audienceId` to send notification using `send` API.
109
+ Use the `maxRetries` request option to configure this behavior.
764
110
 
765
- ```ts
766
- // Example: create audience which would allow sending notification to all users that match the given filter criteria
767
- const { audienceId } = await courier.audiences.put({
768
- id: "<AUDIENCE_ID>",
769
- filter: {
770
- operator: "EQ",
771
- path: "title",
772
- value: "Software Engineer",
773
- },
774
- });
775
-
776
- // To retrieve list of members in a given audience, you can use the following:
777
- const { items: audienceMembers } = await courier.audiences.listMembers(
778
- audienceId
779
- cursor: "<CURSOR>", // optional
780
- );
781
-
782
- // To send a notification to all users that match the given filter criteria, you can use the following:
783
- const { requestId } = await courier.send({
784
- message: {
785
- template: "<TEMPLATE_OR_EVENT_ID>", // This can be inline content as well
786
- to: {
787
- audience_id: audienceId,
788
- },
789
- data: {}, // optional
790
- brand_id: "<BRAND_ID>", //optional
791
- routing: {},
792
- channels: {}, // optional
793
- providers: {}, // optional
794
- },
111
+ ```typescript
112
+ const response = await client.send(..., {
113
+ maxRetries: 0 // override maxRetries at the request level
795
114
  });
796
115
  ```
797
116
 
798
- ### Tenants
799
-
800
- The Tenants API is designed to enable multi-tenant notification workflows. This is useful for defining user to tenant level relationships, especially in the context of B2B applications.
801
-
802
- Use Cases:
117
+ ### Timeouts
803
118
 
804
- - Sending branded notifications on behalf of an organization
805
- - Creating slack-bots on behalf of an organization
119
+ The SDK defaults to a 60 second timeout. Use the `timeoutInSeconds` option to configure this behavior.
806
120
 
807
- #### Creating a Tenant
808
-
809
- ```ts
810
- const { id } = await courier.tenants.createOrReplace("<TENANT_ID>", {
811
- name: "Courier",
812
- user_profile: {
813
- slack: {
814
- access_token: "<SLACK_ACCESS_TOKEN_SCOPED_TO_THE_TENANT>",
815
- },
816
- },
121
+ ```typescript
122
+ const response = await client.send(..., {
123
+ timeoutInSeconds: 30 // override timeout to 30s
817
124
  });
818
125
  ```
819
126
 
820
- #### Retrieving a Tenant
127
+ ### Aborting Requests
821
128
 
822
- ```ts
823
- const tenant = await courier.tenants.get("<TENANT_ID>");
129
+ The SDK allows users to abort requests at any point by passing in an abort signal.
130
+
131
+ ```typescript
132
+ const controller = new AbortController();
133
+ const response = await client.send(..., {
134
+ abortSignal: controller.signal
135
+ });
136
+ controller.abort(); // aborts the request
824
137
  ```
825
138
 
826
- #### Deleting a Tenant
139
+ ### Access Raw Response Data
827
140
 
828
- ```ts
829
- await courier.tenants.delete("<TENANT_ID>");
830
- ```
141
+ The SDK provides access to raw response data, including headers, through the `.withRawResponse()` method.
142
+ The `.withRawResponse()` method returns a promise that results to an object with a `data` and a `rawResponse` property.
831
143
 
832
- #### Listing Tenants
144
+ ```typescript
145
+ const { data, rawResponse } = await client.send(...).withRawResponse();
833
146
 
834
- ```ts
835
- const { items: tenants, has_more } = await courier.tenants.list();
147
+ console.log(data);
148
+ console.log(rawResponse.headers['X-My-Header']);
836
149
  ```
837
150
 
838
- #### Updating user preferences
839
-
840
- Courier currently does not allow creating new topics via the API. You must create topics via the Courier UI. Once a topic is created, you can update a user's preferences for that topic via the API.
151
+ ### Runtime Compatibility
841
152
 
842
- ```ts
843
- await courier.users.preferences.update("<USER_ID>", "<VALID_TOPIC_ID>", {
844
- default_status: "OPTED_IN",
845
- status: "OPTED_OUT",
846
- });
847
- ```
153
+ The SDK defaults to `node-fetch` but will use the global fetch client if present. The SDK works in the following
154
+ runtimes:
848
155
 
849
- #### Getting user preferences
156
+ - Node.js 18+
157
+ - Vercel
158
+ - Cloudflare Workers
159
+ - Deno v1.25+
160
+ - Bun 1.0+
161
+ - React Native
850
162
 
851
- - Get all topic level preferences for a user
163
+ ### Customizing Fetch Client
852
164
 
853
- ```ts
854
- const { items: userPreferences } = await courier.users.preferences.list(
855
- "<USER_ID>"
856
- );
857
- ```
165
+ The SDK provides a way for you to customize the underlying HTTP client / Fetch function. If you're running in an
166
+ unsupported environment, this provides a way for you to break glass and ensure the SDK works.
858
167
 
859
- - Get a specific topic level preference for a user
168
+ ```typescript
169
+ import { CourierClient } from "@trycourier/courier";
860
170
 
861
- ```ts
862
- const userPreference = await courier.users.preferences.get(
863
- "<USER_ID>",
864
- "<VALID_TOPIC_ID>"
865
- );
171
+ const client = new CourierClient({
172
+ ...
173
+ fetcher: // provide your implementation here
174
+ });
866
175
  ```
867
176
 
868
177
  ## Contributing
869
178
 
870
- While we value open-source contributions to this SDK, this library is generated programmatically. Additions made directly to this library would have to be moved over to our generation code, otherwise they would be overwritten upon the next generated release. Feel free to open a PR as a proof of concept, but know that we will not be able to merge it as-is. We suggest opening an issue first to discuss with us!
179
+ While we value open-source contributions to this SDK, this library is generated programmatically.
180
+ Additions made directly to this library would have to be moved over to our generation code,
181
+ otherwise they would be overwritten upon the next generated release. Feel free to open a PR as
182
+ a proof of concept, but know that we will not be able to merge it as-is. We suggest opening
183
+ an issue first to discuss with us!
871
184
 
872
185
  On the other hand, contributions to the README are always very welcome!
873
-
874
- ## License
875
-
876
- [MIT License](http://www.opensource.org/licenses/mit-license.php)
877
-
878
- ## Author
879
-
880
- [Courier](https://github.com/trycourier) ([support@courier.com](mailto:support@courier.com))