chub-dev 0.1.0 → 0.1.2-beta.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.
Files changed (139) hide show
  1. package/README.md +55 -0
  2. package/bin/chub-mcp +2 -0
  3. package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
  4. package/dist/airtable/docs/database/python/DOC.md +1735 -0
  5. package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
  6. package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
  7. package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
  8. package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
  9. package/dist/asana/docs/tasks/DOC.md +1396 -0
  10. package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
  11. package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
  12. package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
  13. package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
  14. package/dist/auth0/docs/identity/python/DOC.md +1199 -0
  15. package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
  16. package/dist/aws/docs/s3/python/DOC.md +1807 -0
  17. package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
  18. package/dist/binance/docs/trading/python/DOC.md +1454 -0
  19. package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
  20. package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
  21. package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
  22. package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
  23. package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
  24. package/dist/clerk/docs/auth/python/DOC.md +274 -0
  25. package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
  26. package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
  27. package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
  28. package/dist/cohere/docs/llm/DOC.md +1335 -0
  29. package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
  30. package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
  31. package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
  32. package/dist/deepgram/docs/speech/python/DOC.md +685 -0
  33. package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
  34. package/dist/deepl/docs/translation/python/DOC.md +944 -0
  35. package/dist/deepseek/docs/llm/DOC.md +1220 -0
  36. package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
  37. package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
  38. package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
  39. package/dist/discord/docs/bot/python/DOC.md +1130 -0
  40. package/dist/elasticsearch/docs/search/DOC.md +1634 -0
  41. package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
  42. package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
  43. package/dist/firebase/docs/auth/DOC.md +1015 -0
  44. package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
  45. package/dist/gemini/docs/genai/python/DOC.md +555 -0
  46. package/dist/github/docs/octokit/DOC.md +1560 -0
  47. package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
  48. package/dist/google/docs/bigquery/python/DOC.md +1503 -0
  49. package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
  50. package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
  51. package/dist/huggingface/docs/transformers/DOC.md +948 -0
  52. package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
  53. package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
  54. package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
  55. package/dist/jira/docs/issues/python/DOC.md +1492 -0
  56. package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
  57. package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
  58. package/dist/landingai-ade/docs/api/DOC.md +620 -0
  59. package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
  60. package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
  61. package/dist/landingai-ade/skills/SKILL.md +489 -0
  62. package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
  63. package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
  64. package/dist/linear/docs/tracker/DOC.md +1554 -0
  65. package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
  66. package/dist/livekit/docs/realtime/python/DOC.md +163 -0
  67. package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
  68. package/dist/meilisearch/docs/search/DOC.md +1241 -0
  69. package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
  70. package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
  71. package/dist/mongodb/docs/atlas/DOC.md +2041 -0
  72. package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
  73. package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
  74. package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
  75. package/dist/okta/docs/identity/python/DOC.md +1401 -0
  76. package/dist/openai/docs/chat/javascript/DOC.md +407 -0
  77. package/dist/openai/docs/chat/python/DOC.md +568 -0
  78. package/dist/paypal/docs/checkout/DOC.md +278 -0
  79. package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
  80. package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
  81. package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
  82. package/dist/plaid/docs/banking/python/DOC.md +1203 -0
  83. package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
  84. package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
  85. package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
  86. package/dist/prisma/docs/orm/python/DOC.md +1317 -0
  87. package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
  88. package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
  89. package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
  90. package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
  91. package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
  92. package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
  93. package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
  94. package/dist/redis/docs/key-value/python/DOC.md +2054 -0
  95. package/dist/registry.json +2817 -0
  96. package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
  97. package/dist/resend/docs/email/DOC.md +1271 -0
  98. package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
  99. package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
  100. package/dist/search-index.json +1 -0
  101. package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
  102. package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
  103. package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
  104. package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
  105. package/dist/shopify/docs/storefront/DOC.md +457 -0
  106. package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
  107. package/dist/slack/docs/workspace/python/DOC.md +271 -0
  108. package/dist/square/docs/payments/javascript/DOC.md +1855 -0
  109. package/dist/square/docs/payments/python/DOC.md +1728 -0
  110. package/dist/stripe/docs/api/DOC.md +1727 -0
  111. package/dist/stripe/docs/payments/DOC.md +1726 -0
  112. package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
  113. package/dist/stytch/docs/auth/python/DOC.md +1962 -0
  114. package/dist/supabase/docs/client/DOC.md +1606 -0
  115. package/dist/twilio/docs/messaging/python/DOC.md +469 -0
  116. package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
  117. package/dist/vercel/docs/platform/DOC.md +1940 -0
  118. package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
  119. package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
  120. package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
  121. package/dist/zendesk/docs/support/python/DOC.md +2297 -0
  122. package/package.json +22 -6
  123. package/skills/get-api-docs/SKILL.md +84 -0
  124. package/src/commands/annotate.js +83 -0
  125. package/src/commands/build.js +12 -1
  126. package/src/commands/feedback.js +150 -0
  127. package/src/commands/get.js +83 -42
  128. package/src/commands/search.js +7 -0
  129. package/src/index.js +43 -17
  130. package/src/lib/analytics.js +90 -0
  131. package/src/lib/annotations.js +57 -0
  132. package/src/lib/bm25.js +170 -0
  133. package/src/lib/cache.js +69 -6
  134. package/src/lib/config.js +8 -3
  135. package/src/lib/identity.js +99 -0
  136. package/src/lib/registry.js +103 -20
  137. package/src/lib/telemetry.js +86 -0
  138. package/src/mcp/server.js +177 -0
  139. package/src/mcp/tools.js +251 -0
@@ -0,0 +1,1271 @@
1
+ ---
2
+ name: email
3
+ description: "Modern email API platform with React Email integration, batch sending, scheduling, webhooks, and domain management"
4
+ metadata:
5
+ languages: "javascript"
6
+ versions: "6.2.2"
7
+ updated-on: "2025-10-26"
8
+ source: maintainer
9
+ tags: "resend,sdk,email,messaging"
10
+ ---
11
+ # Resend Node.js SDK
12
+
13
+ ## Golden Rule
14
+
15
+ **Always use the official `resend` package from npm.** The current version is 6.2.2.
16
+
17
+ ```bash
18
+ npm install resend
19
+ ```
20
+
21
+ Do not use unofficial or deprecated packages like `@philnash/resend` or `resend-client-sdk-python`. The official Resend Node.js SDK is maintained at https://github.com/resend/resend-node.
22
+
23
+ ## Installation
24
+
25
+ Install the Resend SDK using npm, yarn, or pnpm:
26
+
27
+ ```bash
28
+ npm install resend
29
+ ```
30
+
31
+ ## Environment Setup
32
+
33
+ Store your API key in an environment variable:
34
+
35
+ ```bash
36
+ # .env
37
+ RESEND_API_KEY=re_xxxxxxxxx
38
+ ```
39
+
40
+ You can obtain an API key from the Resend Dashboard at https://resend.com/api-keys. The API key will only be shown once, so store it securely immediately.
41
+
42
+ ## Initialization
43
+
44
+ Initialize the Resend client with your API key:
45
+
46
+ ```javascript
47
+ import { Resend } from 'resend';
48
+
49
+ const resend = new Resend(process.env.RESEND_API_KEY);
50
+ ```
51
+
52
+ Or with a hardcoded key (not recommended for production):
53
+
54
+ ```javascript
55
+ const resend = new Resend('re_xxxxxxxxx');
56
+ ```
57
+
58
+ ## Sending Emails
59
+
60
+ ### Basic Email
61
+
62
+ Send a simple HTML email:
63
+
64
+ ```javascript
65
+ import { Resend } from 'resend';
66
+
67
+ const resend = new Resend(process.env.RESEND_API_KEY);
68
+
69
+ const { data, error } = await resend.emails.send({
70
+ from: 'Acme <onboarding@resend.dev>',
71
+ to: ['delivered@resend.dev'],
72
+ subject: 'Hello World',
73
+ html: '<p>Congrats on sending your <strong>first email</strong>!</p>',
74
+ });
75
+
76
+ if (error) {
77
+ console.error(error);
78
+ return;
79
+ }
80
+
81
+ console.log(data);
82
+ // { id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794' }
83
+ ```
84
+
85
+ ### Email with Plain Text
86
+
87
+ Send both HTML and plain text versions:
88
+
89
+ ```javascript
90
+ const { data, error } = await resend.emails.send({
91
+ from: 'Acme <onboarding@resend.dev>',
92
+ to: ['user@example.com'],
93
+ subject: 'Hello World',
94
+ html: '<p>This is the <strong>HTML</strong> version</p>',
95
+ text: 'This is the plain text version',
96
+ });
97
+ ```
98
+
99
+ If you omit the `text` parameter, it will be auto-generated from the HTML.
100
+
101
+ ### Email with Multiple Recipients
102
+
103
+ Send to up to 50 recipients:
104
+
105
+ ```javascript
106
+ const { data, error } = await resend.emails.send({
107
+ from: 'Acme <onboarding@resend.dev>',
108
+ to: ['user1@example.com', 'user2@example.com', 'user3@example.com'],
109
+ subject: 'Hello World',
110
+ html: '<p>Hello everyone!</p>',
111
+ });
112
+ ```
113
+
114
+ ### Email with CC and BCC
115
+
116
+ ```javascript
117
+ const { data, error } = await resend.emails.send({
118
+ from: 'Acme <onboarding@resend.dev>',
119
+ to: ['primary@example.com'],
120
+ cc: ['cc1@example.com', 'cc2@example.com'],
121
+ bcc: ['bcc1@example.com', 'bcc2@example.com'],
122
+ subject: 'Hello World',
123
+ html: '<p>Email with CC and BCC</p>',
124
+ });
125
+ ```
126
+
127
+ ### Email with Reply-To
128
+
129
+ ```javascript
130
+ const { data, error } = await resend.emails.send({
131
+ from: 'Acme <onboarding@resend.dev>',
132
+ to: ['user@example.com'],
133
+ replyTo: 'support@acme.com',
134
+ subject: 'Hello World',
135
+ html: '<p>Reply to this email!</p>',
136
+ });
137
+ ```
138
+
139
+ Multiple reply-to addresses:
140
+
141
+ ```javascript
142
+ const { data, error } = await resend.emails.send({
143
+ from: 'Acme <onboarding@resend.dev>',
144
+ to: ['user@example.com'],
145
+ replyTo: ['support@acme.com', 'help@acme.com'],
146
+ subject: 'Hello World',
147
+ html: '<p>Reply to this email!</p>',
148
+ });
149
+ ```
150
+
151
+ ### Email with Custom Headers
152
+
153
+ ```javascript
154
+ const { data, error } = await resend.emails.send({
155
+ from: 'Acme <onboarding@resend.dev>',
156
+ to: ['user@example.com'],
157
+ subject: 'Hello World',
158
+ html: '<p>Email with custom headers</p>',
159
+ headers: {
160
+ 'X-Entity-Ref-ID': '123456789',
161
+ 'X-Custom-Header': 'Custom Value',
162
+ },
163
+ });
164
+ ```
165
+
166
+ ### Email with Tags
167
+
168
+ Tags are custom key/value pairs for tracking and categorizing emails:
169
+
170
+ ```javascript
171
+ const { data, error } = await resend.emails.send({
172
+ from: 'Acme <onboarding@resend.dev>',
173
+ to: ['user@example.com'],
174
+ subject: 'Hello World',
175
+ html: '<p>Email with tags</p>',
176
+ tags: [
177
+ { name: 'category', value: 'confirm_email' },
178
+ { name: 'user_id', value: '12345' },
179
+ ],
180
+ });
181
+ ```
182
+
183
+ ### Email with Attachments
184
+
185
+ Attachments support up to 40MB per email after Base64 encoding:
186
+
187
+ ```javascript
188
+ import fs from 'fs';
189
+
190
+ const { data, error } = await resend.emails.send({
191
+ from: 'Acme <onboarding@resend.dev>',
192
+ to: ['user@example.com'],
193
+ subject: 'Invoice',
194
+ html: '<p>Please find your invoice attached</p>',
195
+ attachments: [
196
+ {
197
+ filename: 'invoice.pdf',
198
+ content: fs.readFileSync('./invoice.pdf'),
199
+ },
200
+ ],
201
+ });
202
+ ```
203
+
204
+ Attachment with custom content type:
205
+
206
+ ```javascript
207
+ const { data, error } = await resend.emails.send({
208
+ from: 'Acme <onboarding@resend.dev>',
209
+ to: ['user@example.com'],
210
+ subject: 'Report',
211
+ html: '<p>Your report is attached</p>',
212
+ attachments: [
213
+ {
214
+ filename: 'report.csv',
215
+ content: 'Name,Email\nJohn,john@example.com\n',
216
+ contentType: 'text/csv',
217
+ },
218
+ ],
219
+ });
220
+ ```
221
+
222
+ Multiple attachments:
223
+
224
+ ```javascript
225
+ const { data, error } = await resend.emails.send({
226
+ from: 'Acme <onboarding@resend.dev>',
227
+ to: ['user@example.com'],
228
+ subject: 'Multiple Files',
229
+ html: '<p>Multiple files attached</p>',
230
+ attachments: [
231
+ {
232
+ filename: 'document1.pdf',
233
+ content: fs.readFileSync('./document1.pdf'),
234
+ },
235
+ {
236
+ filename: 'document2.pdf',
237
+ content: fs.readFileSync('./document2.pdf'),
238
+ },
239
+ ],
240
+ });
241
+ ```
242
+
243
+ ### Scheduled Email
244
+
245
+ Schedule an email using natural language or ISO 8601 format. Emails can be scheduled up to 30 days in advance.
246
+
247
+ Natural language examples:
248
+
249
+ ```javascript
250
+ const { data, error } = await resend.emails.send({
251
+ from: 'Acme <onboarding@resend.dev>',
252
+ to: ['user@example.com'],
253
+ subject: 'Scheduled Email',
254
+ html: '<p>This email was scheduled</p>',
255
+ scheduledAt: 'in 1 hour',
256
+ });
257
+ ```
258
+
259
+ ```javascript
260
+ const { data, error } = await resend.emails.send({
261
+ from: 'Acme <onboarding@resend.dev>',
262
+ to: ['user@example.com'],
263
+ subject: 'Scheduled Email',
264
+ html: '<p>This email was scheduled</p>',
265
+ scheduledAt: 'tomorrow at 9am',
266
+ });
267
+ ```
268
+
269
+ ```javascript
270
+ const { data, error } = await resend.emails.send({
271
+ from: 'Acme <onboarding@resend.dev>',
272
+ to: ['user@example.com'],
273
+ subject: 'Scheduled Email',
274
+ html: '<p>This email was scheduled</p>',
275
+ scheduledAt: 'Friday at 3pm ET',
276
+ });
277
+ ```
278
+
279
+ ISO 8601 format:
280
+
281
+ ```javascript
282
+ const { data, error } = await resend.emails.send({
283
+ from: 'Acme <onboarding@resend.dev>',
284
+ to: ['user@example.com'],
285
+ subject: 'Scheduled Email',
286
+ html: '<p>This email was scheduled</p>',
287
+ scheduledAt: '2024-08-05T11:52:01.858Z',
288
+ });
289
+ ```
290
+
291
+ ### Email with React Components
292
+
293
+ The Node.js SDK supports React components for email templates:
294
+
295
+ ```javascript
296
+ import { Resend } from 'resend';
297
+ import { EmailTemplate } from './email-template';
298
+
299
+ const resend = new Resend(process.env.RESEND_API_KEY);
300
+
301
+ const { data, error } = await resend.emails.send({
302
+ from: 'Acme <onboarding@resend.dev>',
303
+ to: ['user@example.com'],
304
+ subject: 'Welcome',
305
+ react: EmailTemplate({ firstName: 'John' }),
306
+ });
307
+ ```
308
+
309
+ Example React email component:
310
+
311
+ ```jsx
312
+ // email-template.jsx
313
+ import * as React from 'react';
314
+
315
+ export const EmailTemplate = ({ firstName }) => (
316
+ <div>
317
+ <h1>Welcome, {firstName}!</h1>
318
+ <p>Thanks for signing up.</p>
319
+ </div>
320
+ );
321
+ ```
322
+
323
+ With `@react-email/components`:
324
+
325
+ ```jsx
326
+ import { Html, Button } from '@react-email/components';
327
+
328
+ export const EmailTemplate = ({ url }) => (
329
+ <Html>
330
+ <Button href={url}>Click me</Button>
331
+ </Html>
332
+ );
333
+ ```
334
+
335
+ ### Idempotency
336
+
337
+ Use idempotency keys to prevent duplicate sends. Keys expire after 24 hours and must be max 256 characters:
338
+
339
+ ```javascript
340
+ const { data, error } = await resend.emails.send({
341
+ from: 'Acme <onboarding@resend.dev>',
342
+ to: ['user@example.com'],
343
+ subject: 'Hello World',
344
+ html: '<p>This is idempotent</p>',
345
+ }, {
346
+ headers: {
347
+ 'Idempotency-Key': 'unique-key-123456',
348
+ },
349
+ });
350
+ ```
351
+
352
+ ## Batch Emails
353
+
354
+ Send up to 100 emails in a single API call. Note that `attachments` and `scheduledAt` are not supported in batch mode.
355
+
356
+ ### Basic Batch Send
357
+
358
+ ```javascript
359
+ const { data, error } = await resend.batch.send([
360
+ {
361
+ from: 'Acme <onboarding@resend.dev>',
362
+ to: ['user1@example.com'],
363
+ subject: 'Hello User 1',
364
+ html: '<p>Hello User 1</p>',
365
+ },
366
+ {
367
+ from: 'Acme <onboarding@resend.dev>',
368
+ to: ['user2@example.com'],
369
+ subject: 'Hello User 2',
370
+ html: '<p>Hello User 2</p>',
371
+ },
372
+ {
373
+ from: 'Acme <onboarding@resend.dev>',
374
+ to: ['user3@example.com'],
375
+ subject: 'Hello User 3',
376
+ html: '<p>Hello User 3</p>',
377
+ },
378
+ ]);
379
+
380
+ console.log(data);
381
+ // [
382
+ // { id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794' },
383
+ // { id: '5d3a4f2e-8f7b-4c1d-9a3e-2b6c1e8f9a0b' },
384
+ // { id: '7e9f1a3c-2d4b-5e6f-8a9c-3d4e5f6a7b8c' }
385
+ // ]
386
+ ```
387
+
388
+ ### Batch with Tags
389
+
390
+ ```javascript
391
+ const { data, error } = await resend.batch.send([
392
+ {
393
+ from: 'Acme <onboarding@resend.dev>',
394
+ to: ['user1@example.com'],
395
+ subject: 'Hello',
396
+ html: '<p>Hello</p>',
397
+ tags: [{ name: 'category', value: 'welcome' }],
398
+ },
399
+ {
400
+ from: 'Acme <onboarding@resend.dev>',
401
+ to: ['user2@example.com'],
402
+ subject: 'Hello',
403
+ html: '<p>Hello</p>',
404
+ tags: [{ name: 'category', value: 'welcome' }],
405
+ },
406
+ ]);
407
+ ```
408
+
409
+ ### Permissive Validation Mode
410
+
411
+ By default, if any email in a batch is invalid, the entire batch fails. Use permissive mode to process valid emails and return errors for invalid ones:
412
+
413
+ ```javascript
414
+ const { data, error } = await resend.batch.send(
415
+ [
416
+ {
417
+ from: 'Acme <onboarding@resend.dev>',
418
+ to: ['valid@example.com'],
419
+ subject: 'Valid Email',
420
+ html: '<p>This is valid</p>',
421
+ },
422
+ {
423
+ from: 'invalid-email',
424
+ to: ['user@example.com'],
425
+ subject: 'Invalid Email',
426
+ html: '<p>This has invalid from address</p>',
427
+ },
428
+ ],
429
+ {
430
+ headers: {
431
+ 'X-Resend-Validation-Mode': 'permissive',
432
+ },
433
+ }
434
+ );
435
+
436
+ console.log(data);
437
+ // {
438
+ // data: [{ id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794' }],
439
+ // errors: [{ message: 'Invalid from address', index: 1 }]
440
+ // }
441
+ ```
442
+
443
+ ## Managing Emails
444
+
445
+ ### Retrieve Email by ID
446
+
447
+ Get details about a specific email:
448
+
449
+ ```javascript
450
+ const { data, error } = await resend.emails.get(
451
+ '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'
452
+ );
453
+
454
+ console.log(data);
455
+ // {
456
+ // object: 'email',
457
+ // id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794',
458
+ // to: ['delivered@resend.dev'],
459
+ // from: 'Acme <onboarding@resend.dev>',
460
+ // created_at: '2023-04-03T22:13:42.674981+00:00',
461
+ // subject: 'Hello World',
462
+ // html: 'Congrats on sending your <strong>first email</strong>!',
463
+ // text: null,
464
+ // bcc: [],
465
+ // cc: [],
466
+ // reply_to: [],
467
+ // last_event: 'delivered',
468
+ // scheduled_at: null
469
+ // }
470
+ ```
471
+
472
+ ### Update Scheduled Email
473
+
474
+ Update the scheduled time for a scheduled email:
475
+
476
+ ```javascript
477
+ const oneHourFromNow = new Date(Date.now() + 1000 * 60 * 60).toISOString();
478
+
479
+ const { data, error } = await resend.emails.update({
480
+ id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794',
481
+ scheduledAt: oneHourFromNow,
482
+ });
483
+
484
+ console.log(data);
485
+ // {
486
+ // object: 'email',
487
+ // id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'
488
+ // }
489
+ ```
490
+
491
+ With natural language:
492
+
493
+ ```javascript
494
+ const { data, error } = await resend.emails.update({
495
+ id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794',
496
+ scheduledAt: 'in 2 hours',
497
+ });
498
+ ```
499
+
500
+ ### Cancel Scheduled Email
501
+
502
+ Cancel a scheduled email that hasn't been sent yet:
503
+
504
+ ```javascript
505
+ const { data, error } = await resend.emails.cancel(
506
+ '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'
507
+ );
508
+
509
+ console.log(data);
510
+ // {
511
+ // object: 'email',
512
+ // id: '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794'
513
+ // }
514
+ ```
515
+
516
+ Note: Once an email is canceled, it cannot be rescheduled.
517
+
518
+ ## Audiences
519
+
520
+ Audiences allow you to group and manage contacts for broadcasting.
521
+
522
+ ### Create Audience
523
+
524
+ ```javascript
525
+ const { data, error } = await resend.audiences.create({
526
+ name: 'Registered Users',
527
+ });
528
+
529
+ console.log(data);
530
+ // {
531
+ // object: 'audience',
532
+ // id: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
533
+ // name: 'Registered Users'
534
+ // }
535
+ ```
536
+
537
+ ### Retrieve Audience
538
+
539
+ ```javascript
540
+ const { data, error } = await resend.audiences.get(
541
+ '78261eea-8f8b-4381-83c6-79fa7120f1cf'
542
+ );
543
+ ```
544
+
545
+ ### List Audiences
546
+
547
+ ```javascript
548
+ const { data, error } = await resend.audiences.list();
549
+
550
+ console.log(data);
551
+ // {
552
+ // object: 'list',
553
+ // data: [
554
+ // {
555
+ // id: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
556
+ // name: 'Registered Users',
557
+ // created_at: '2023-10-06T23:47:56.678Z'
558
+ // }
559
+ // ]
560
+ // }
561
+ ```
562
+
563
+ ### Delete Audience
564
+
565
+ ```javascript
566
+ const { data, error } = await resend.audiences.remove(
567
+ '78261eea-8f8b-4381-83c6-79fa7120f1cf'
568
+ );
569
+ ```
570
+
571
+ ## Contacts
572
+
573
+ Manage individual contacts within audiences.
574
+
575
+ ### Create Contact
576
+
577
+ ```javascript
578
+ const { data, error } = await resend.contacts.create({
579
+ audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
580
+ email: 'user@example.com',
581
+ firstName: 'John',
582
+ lastName: 'Doe',
583
+ unsubscribed: false,
584
+ });
585
+
586
+ console.log(data);
587
+ // {
588
+ // object: 'contact',
589
+ // id: '479e3145-dd38-476b-932c-529ceb705947'
590
+ // }
591
+ ```
592
+
593
+ ### Create Contact (Minimal)
594
+
595
+ ```javascript
596
+ const { data, error } = await resend.contacts.create({
597
+ audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
598
+ email: 'user@example.com',
599
+ });
600
+ ```
601
+
602
+ ### Retrieve Contact
603
+
604
+ ```javascript
605
+ const { data, error } = await resend.contacts.get({
606
+ audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
607
+ id: '479e3145-dd38-476b-932c-529ceb705947',
608
+ });
609
+ ```
610
+
611
+ ### List Contacts
612
+
613
+ ```javascript
614
+ const { data, error } = await resend.contacts.list({
615
+ audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
616
+ });
617
+
618
+ console.log(data);
619
+ // {
620
+ // object: 'list',
621
+ // data: [
622
+ // {
623
+ // id: '479e3145-dd38-476b-932c-529ceb705947',
624
+ // email: 'user@example.com',
625
+ // first_name: 'John',
626
+ // last_name: 'Doe',
627
+ // created_at: '2023-10-06T23:47:56.678Z',
628
+ // unsubscribed: false
629
+ // }
630
+ // ]
631
+ // }
632
+ ```
633
+
634
+ ### Update Contact
635
+
636
+ ```javascript
637
+ const { data, error } = await resend.contacts.update({
638
+ audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
639
+ id: '479e3145-dd38-476b-932c-529ceb705947',
640
+ firstName: 'Jane',
641
+ unsubscribed: true,
642
+ });
643
+ ```
644
+
645
+ ### Delete Contact
646
+
647
+ ```javascript
648
+ const { data, error } = await resend.contacts.remove({
649
+ audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
650
+ id: '479e3145-dd38-476b-932c-529ceb705947',
651
+ });
652
+ ```
653
+
654
+ ## Broadcasts
655
+
656
+ Broadcasts allow you to send emails to entire audiences.
657
+
658
+ ### Create Broadcast
659
+
660
+ ```javascript
661
+ const { data, error } = await resend.broadcasts.create({
662
+ audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
663
+ from: 'Acme <newsletter@acme.com>',
664
+ subject: 'Monthly Newsletter',
665
+ html: 'Hi {{{FIRST_NAME|there}}}, you can unsubscribe here: {{{RESEND_UNSUBSCRIBE_URL}}}',
666
+ name: 'October Newsletter',
667
+ });
668
+
669
+ console.log(data);
670
+ // {
671
+ // id: '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'
672
+ // }
673
+ ```
674
+
675
+ ### Create Broadcast with React
676
+
677
+ ```javascript
678
+ import { NewsletterTemplate } from './newsletter-template';
679
+
680
+ const { data, error } = await resend.broadcasts.create({
681
+ audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
682
+ from: 'Acme <newsletter@acme.com>',
683
+ subject: 'Monthly Newsletter',
684
+ react: NewsletterTemplate(),
685
+ });
686
+ ```
687
+
688
+ ### Broadcast Template Variables
689
+
690
+ Use template variables in broadcasts:
691
+
692
+ - `{{{FIRST_NAME}}}` - Contact's first name
693
+ - `{{{LAST_NAME}}}` - Contact's last name
694
+ - `{{{EMAIL}}}` - Contact's email
695
+ - `{{{RESEND_UNSUBSCRIBE_URL}}}` - Unsubscribe URL
696
+
697
+ With fallback values:
698
+
699
+ ```javascript
700
+ const { data, error } = await resend.broadcasts.create({
701
+ audienceId: '78261eea-8f8b-4381-83c6-79fa7120f1cf',
702
+ from: 'Acme <newsletter@acme.com>',
703
+ subject: 'Hello {{{FIRST_NAME|Friend}}}',
704
+ html: '<p>Hi {{{FIRST_NAME|there}}},</p><p>Thanks for subscribing!</p>',
705
+ });
706
+ ```
707
+
708
+ ### Send Broadcast Immediately
709
+
710
+ ```javascript
711
+ const { data, error } = await resend.broadcasts.send(
712
+ '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'
713
+ );
714
+
715
+ console.log(data);
716
+ // {
717
+ // id: '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'
718
+ // }
719
+ ```
720
+
721
+ ### Send Broadcast with Scheduling
722
+
723
+ ```javascript
724
+ const { data, error } = await resend.broadcasts.send(
725
+ '559ac32e-9ef5-46fb-82a1-b76b840c0f7b',
726
+ {
727
+ scheduledAt: 'tomorrow at 9am',
728
+ }
729
+ );
730
+ ```
731
+
732
+ ```javascript
733
+ const { data, error } = await resend.broadcasts.send(
734
+ '559ac32e-9ef5-46fb-82a1-b76b840c0f7b',
735
+ {
736
+ scheduledAt: '2024-08-05T11:52:01.858Z',
737
+ }
738
+ );
739
+ ```
740
+
741
+ ### Retrieve Broadcast
742
+
743
+ ```javascript
744
+ const { data, error } = await resend.broadcasts.get(
745
+ '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'
746
+ );
747
+ ```
748
+
749
+ ### List Broadcasts
750
+
751
+ ```javascript
752
+ const { data, error } = await resend.broadcasts.list();
753
+ ```
754
+
755
+ ### Update Broadcast
756
+
757
+ ```javascript
758
+ const { data, error } = await resend.broadcasts.update({
759
+ id: '559ac32e-9ef5-46fb-82a1-b76b840c0f7b',
760
+ subject: 'Updated Newsletter Subject',
761
+ html: '<p>Updated content</p>',
762
+ });
763
+ ```
764
+
765
+ ### Delete Broadcast
766
+
767
+ ```javascript
768
+ const { data, error } = await resend.broadcasts.remove(
769
+ '559ac32e-9ef5-46fb-82a1-b76b840c0f7b'
770
+ );
771
+ ```
772
+
773
+ ## Domains
774
+
775
+ Manage domains for sending emails.
776
+
777
+ ### Create Domain
778
+
779
+ ```javascript
780
+ const { data, error } = await resend.domains.create({
781
+ name: 'example.com',
782
+ });
783
+
784
+ console.log(data);
785
+ // {
786
+ // id: 'd91cd9bd-1176-453e-8fc1-35364d380206',
787
+ // name: 'example.com',
788
+ // status: 'not_started',
789
+ // records: [
790
+ // {
791
+ // record: 'SPF',
792
+ // name: 'example.com',
793
+ // type: 'TXT',
794
+ // value: 'v=spf1 include:_spf.resend.com ~all'
795
+ // },
796
+ // {
797
+ // record: 'DKIM',
798
+ // name: 'resend._domainkey.example.com',
799
+ // type: 'TXT',
800
+ // value: 'p=...'
801
+ // }
802
+ // ]
803
+ // }
804
+ ```
805
+
806
+ ### Retrieve Domain
807
+
808
+ ```javascript
809
+ const { data, error } = await resend.domains.get(
810
+ 'd91cd9bd-1176-453e-8fc1-35364d380206'
811
+ );
812
+ ```
813
+
814
+ ### List Domains
815
+
816
+ ```javascript
817
+ const { data, error } = await resend.domains.list();
818
+
819
+ console.log(data);
820
+ // {
821
+ // object: 'list',
822
+ // data: [
823
+ // {
824
+ // id: 'd91cd9bd-1176-453e-8fc1-35364d380206',
825
+ // name: 'example.com',
826
+ // status: 'verified',
827
+ // created_at: '2023-04-03T22:13:42.674981+00:00'
828
+ // }
829
+ // ]
830
+ // }
831
+ ```
832
+
833
+ ### Verify Domain
834
+
835
+ After adding DNS records, verify the domain:
836
+
837
+ ```javascript
838
+ const { data, error } = await resend.domains.verify(
839
+ 'd91cd9bd-1176-453e-8fc1-35364d380206'
840
+ );
841
+
842
+ console.log(data);
843
+ // {
844
+ // object: 'domain',
845
+ // id: 'd91cd9bd-1176-453e-8fc1-35364d380206',
846
+ // status: 'verified'
847
+ // }
848
+ ```
849
+
850
+ ### Update Domain
851
+
852
+ ```javascript
853
+ const { data, error } = await resend.domains.update({
854
+ id: 'd91cd9bd-1176-453e-8fc1-35364d380206',
855
+ clickTracking: true,
856
+ openTracking: true,
857
+ });
858
+ ```
859
+
860
+ ### Delete Domain
861
+
862
+ ```javascript
863
+ const { data, error } = await resend.domains.remove(
864
+ 'd91cd9bd-1176-453e-8fc1-35364d380206'
865
+ );
866
+ ```
867
+
868
+ ## API Keys
869
+
870
+ Manage API keys programmatically.
871
+
872
+ ### Create API Key
873
+
874
+ ```javascript
875
+ const { data, error } = await resend.apiKeys.create({
876
+ name: 'Production',
877
+ permission: 'full_access',
878
+ });
879
+
880
+ console.log(data);
881
+ // {
882
+ // id: 'b6d24b8e-af0b-4c3c-be0c-359bbd97381e',
883
+ // token: 're_xxxxxxxxx'
884
+ // }
885
+ ```
886
+
887
+ Available permissions:
888
+ - `full_access` - Can create, delete, get, and update any resource
889
+ - `sending_access` - Can only send emails
890
+
891
+ Create sending-only API key:
892
+
893
+ ```javascript
894
+ const { data, error } = await resend.apiKeys.create({
895
+ name: 'Sending Key',
896
+ permission: 'sending_access',
897
+ });
898
+ ```
899
+
900
+ Restrict to specific domain:
901
+
902
+ ```javascript
903
+ const { data, error } = await resend.apiKeys.create({
904
+ name: 'Domain-Specific Key',
905
+ permission: 'sending_access',
906
+ domainId: 'd91cd9bd-1176-453e-8fc1-35364d380206',
907
+ });
908
+ ```
909
+
910
+ ### List API Keys
911
+
912
+ ```javascript
913
+ const { data, error } = await resend.apiKeys.list();
914
+
915
+ console.log(data);
916
+ // {
917
+ // object: 'list',
918
+ // has_more: false,
919
+ // data: [
920
+ // {
921
+ // id: '91f3200a-df72-4654-b0cd-f202395f5354',
922
+ // name: 'Production',
923
+ // created_at: '2023-04-08T00:11:13.110779+00:00'
924
+ // }
925
+ // ]
926
+ // }
927
+ ```
928
+
929
+ ### Delete API Key
930
+
931
+ ```javascript
932
+ const { data, error } = await resend.apiKeys.remove(
933
+ 'b6d24b8e-af0b-4c3c-be0c-359bbd97381e'
934
+ );
935
+ ```
936
+
937
+ ## Error Handling
938
+
939
+ All API methods return an object with `data` and `error` properties:
940
+
941
+ ```javascript
942
+ const { data, error } = await resend.emails.send({
943
+ from: 'Acme <onboarding@resend.dev>',
944
+ to: ['user@example.com'],
945
+ subject: 'Hello',
946
+ html: '<p>Hello</p>',
947
+ });
948
+
949
+ if (error) {
950
+ console.error('Failed to send email:', error);
951
+ return;
952
+ }
953
+
954
+ console.log('Email sent successfully:', data.id);
955
+ ```
956
+
957
+ Common error scenarios:
958
+
959
+ ```javascript
960
+ // Missing required fields
961
+ const { data, error } = await resend.emails.send({
962
+ from: 'Acme <onboarding@resend.dev>',
963
+ to: ['user@example.com'],
964
+ // Missing subject
965
+ html: '<p>Hello</p>',
966
+ });
967
+ // error: { message: 'Missing required parameter: subject' }
968
+
969
+ // Invalid API key
970
+ const resend = new Resend('invalid_key');
971
+ const { data, error } = await resend.emails.send({...});
972
+ // error: { message: 'Invalid API key' }
973
+
974
+ // Unverified domain
975
+ const { data, error } = await resend.emails.send({
976
+ from: 'user@unverified-domain.com',
977
+ to: ['user@example.com'],
978
+ subject: 'Hello',
979
+ html: '<p>Hello</p>',
980
+ });
981
+ // error: { message: 'Domain not verified' }
982
+
983
+ // Rate limit exceeded
984
+ // error: { message: 'Rate limit exceeded' }
985
+ ```
986
+
987
+ ## Complete Examples
988
+
989
+ ### Basic Email Sending
990
+
991
+ ```javascript
992
+ import { Resend } from 'resend';
993
+
994
+ const resend = new Resend(process.env.RESEND_API_KEY);
995
+
996
+ async function sendWelcomeEmail(userEmail, userName) {
997
+ const { data, error } = await resend.emails.send({
998
+ from: 'Acme <welcome@acme.com>',
999
+ to: [userEmail],
1000
+ subject: `Welcome to Acme, ${userName}!`,
1001
+ html: `
1002
+ <h1>Welcome, ${userName}!</h1>
1003
+ <p>Thanks for signing up. We're excited to have you on board.</p>
1004
+ <p>Get started by visiting your dashboard.</p>
1005
+ `,
1006
+ });
1007
+
1008
+ if (error) {
1009
+ throw new Error(`Failed to send welcome email: ${error.message}`);
1010
+ }
1011
+
1012
+ return data.id;
1013
+ }
1014
+
1015
+ // Usage
1016
+ await sendWelcomeEmail('user@example.com', 'John Doe');
1017
+ ```
1018
+
1019
+ ### Scheduled Email with Attachment
1020
+
1021
+ ```javascript
1022
+ import { Resend } from 'resend';
1023
+ import fs from 'fs';
1024
+
1025
+ const resend = new Resend(process.env.RESEND_API_KEY);
1026
+
1027
+ async function sendScheduledReport(recipient, reportPath, sendTime) {
1028
+ const { data, error } = await resend.emails.send({
1029
+ from: 'Reports <reports@acme.com>',
1030
+ to: [recipient],
1031
+ subject: 'Weekly Report',
1032
+ html: '<p>Your weekly report is attached.</p>',
1033
+ attachments: [
1034
+ {
1035
+ filename: 'weekly-report.pdf',
1036
+ content: fs.readFileSync(reportPath),
1037
+ contentType: 'application/pdf',
1038
+ },
1039
+ ],
1040
+ scheduledAt: sendTime,
1041
+ tags: [
1042
+ { name: 'type', value: 'report' },
1043
+ { name: 'frequency', value: 'weekly' },
1044
+ ],
1045
+ });
1046
+
1047
+ if (error) {
1048
+ throw new Error(`Failed to schedule report: ${error.message}`);
1049
+ }
1050
+
1051
+ return data.id;
1052
+ }
1053
+
1054
+ // Usage
1055
+ await sendScheduledReport(
1056
+ 'manager@example.com',
1057
+ './reports/weekly.pdf',
1058
+ 'Friday at 9am'
1059
+ );
1060
+ ```
1061
+
1062
+ ### Newsletter Broadcast
1063
+
1064
+ ```javascript
1065
+ import { Resend } from 'resend';
1066
+
1067
+ const resend = new Resend(process.env.RESEND_API_KEY);
1068
+
1069
+ async function sendNewsletter(audienceId, content) {
1070
+ // Create broadcast
1071
+ const { data: broadcast, error: createError } = await resend.broadcasts.create({
1072
+ audienceId: audienceId,
1073
+ from: 'Newsletter <newsletter@acme.com>',
1074
+ subject: 'Monthly Update - October 2024',
1075
+ html: `
1076
+ <h1>Hi {{{FIRST_NAME|there}}}!</h1>
1077
+ ${content}
1078
+ <p><a href="{{{RESEND_UNSUBSCRIBE_URL}}}">Unsubscribe</a></p>
1079
+ `,
1080
+ name: 'October 2024 Newsletter',
1081
+ });
1082
+
1083
+ if (createError) {
1084
+ throw new Error(`Failed to create broadcast: ${createError.message}`);
1085
+ }
1086
+
1087
+ // Send immediately
1088
+ const { data: sent, error: sendError } = await resend.broadcasts.send(
1089
+ broadcast.id
1090
+ );
1091
+
1092
+ if (sendError) {
1093
+ throw new Error(`Failed to send broadcast: ${sendError.message}`);
1094
+ }
1095
+
1096
+ return sent.id;
1097
+ }
1098
+
1099
+ // Usage
1100
+ await sendNewsletter(
1101
+ '78261eea-8f8b-4381-83c6-79fa7120f1cf',
1102
+ '<p>Here is what is new this month...</p>'
1103
+ );
1104
+ ```
1105
+
1106
+ ### Batch Email with Error Handling
1107
+
1108
+ ```javascript
1109
+ import { Resend } from 'resend';
1110
+
1111
+ const resend = new Resend(process.env.RESEND_API_KEY);
1112
+
1113
+ async function sendBatchNotifications(users) {
1114
+ const emails = users.map(user => ({
1115
+ from: 'Notifications <notifications@acme.com>',
1116
+ to: [user.email],
1117
+ subject: 'Important Update',
1118
+ html: `<p>Hi ${user.name}, we have an important update for you.</p>`,
1119
+ tags: [{ name: 'user_id', value: user.id }],
1120
+ }));
1121
+
1122
+ const { data, error } = await resend.batch.send(emails, {
1123
+ headers: {
1124
+ 'X-Resend-Validation-Mode': 'permissive',
1125
+ },
1126
+ });
1127
+
1128
+ if (error) {
1129
+ throw new Error(`Batch send failed: ${error.message}`);
1130
+ }
1131
+
1132
+ // Handle partial failures
1133
+ if (data.errors && data.errors.length > 0) {
1134
+ console.warn('Some emails failed:', data.errors);
1135
+ }
1136
+
1137
+ return {
1138
+ successful: data.data.length,
1139
+ failed: data.errors?.length || 0,
1140
+ emailIds: data.data.map(d => d.id),
1141
+ };
1142
+ }
1143
+
1144
+ // Usage
1145
+ const users = [
1146
+ { id: '1', email: 'user1@example.com', name: 'User 1' },
1147
+ { id: '2', email: 'user2@example.com', name: 'User 2' },
1148
+ { id: '3', email: 'user3@example.com', name: 'User 3' },
1149
+ ];
1150
+
1151
+ const result = await sendBatchNotifications(users);
1152
+ console.log(`Sent ${result.successful} emails, ${result.failed} failed`);
1153
+ ```
1154
+
1155
+ ### Managing Audience and Contacts
1156
+
1157
+ ```javascript
1158
+ import { Resend } from 'resend';
1159
+
1160
+ const resend = new Resend(process.env.RESEND_API_KEY);
1161
+
1162
+ async function setupMarketingList(listName, contacts) {
1163
+ // Create audience
1164
+ const { data: audience, error: audienceError } = await resend.audiences.create({
1165
+ name: listName,
1166
+ });
1167
+
1168
+ if (audienceError) {
1169
+ throw new Error(`Failed to create audience: ${audienceError.message}`);
1170
+ }
1171
+
1172
+ console.log(`Created audience: ${audience.id}`);
1173
+
1174
+ // Add contacts
1175
+ const results = [];
1176
+ for (const contact of contacts) {
1177
+ const { data, error } = await resend.contacts.create({
1178
+ audienceId: audience.id,
1179
+ email: contact.email,
1180
+ firstName: contact.firstName,
1181
+ lastName: contact.lastName,
1182
+ });
1183
+
1184
+ if (error) {
1185
+ console.error(`Failed to add ${contact.email}:`, error.message);
1186
+ } else {
1187
+ results.push(data.id);
1188
+ }
1189
+ }
1190
+
1191
+ return {
1192
+ audienceId: audience.id,
1193
+ contactsAdded: results.length,
1194
+ };
1195
+ }
1196
+
1197
+ // Usage
1198
+ const contacts = [
1199
+ { email: 'john@example.com', firstName: 'John', lastName: 'Doe' },
1200
+ { email: 'jane@example.com', firstName: 'Jane', lastName: 'Smith' },
1201
+ ];
1202
+
1203
+ const result = await setupMarketingList('Q4 Campaign', contacts);
1204
+ console.log(`Setup complete: ${result.contactsAdded} contacts added`);
1205
+ ```
1206
+
1207
+ ### Cancel and Reschedule
1208
+
1209
+ ```javascript
1210
+ import { Resend } from 'resend';
1211
+
1212
+ const resend = new Resend(process.env.RESEND_API_KEY);
1213
+
1214
+ async function rescheduleEmail(emailId, newTime) {
1215
+ // Update scheduled time
1216
+ const { data, error } = await resend.emails.update({
1217
+ id: emailId,
1218
+ scheduledAt: newTime,
1219
+ });
1220
+
1221
+ if (error) {
1222
+ throw new Error(`Failed to reschedule: ${error.message}`);
1223
+ }
1224
+
1225
+ return data.id;
1226
+ }
1227
+
1228
+ async function cancelScheduledEmail(emailId) {
1229
+ const { data, error } = await resend.emails.cancel(emailId);
1230
+
1231
+ if (error) {
1232
+ throw new Error(`Failed to cancel: ${error.message}`);
1233
+ }
1234
+
1235
+ return data.id;
1236
+ }
1237
+
1238
+ // Usage
1239
+ const emailId = '49a3999c-0ce1-4ea6-ab68-afcd6dc2e794';
1240
+
1241
+ // Reschedule for 2 hours later
1242
+ await rescheduleEmail(emailId, 'in 2 hours');
1243
+
1244
+ // Or cancel completely
1245
+ await cancelScheduledEmail(emailId);
1246
+ ```
1247
+
1248
+ ## TypeScript Support
1249
+
1250
+ The Resend SDK is written in TypeScript and includes full type definitions:
1251
+
1252
+ ```typescript
1253
+ import { Resend } from 'resend';
1254
+ import type { CreateEmailOptions, CreateEmailResponse } from 'resend';
1255
+
1256
+ const resend = new Resend(process.env.RESEND_API_KEY);
1257
+
1258
+ async function sendEmail(
1259
+ options: CreateEmailOptions
1260
+ ): Promise<CreateEmailResponse> {
1261
+ const { data, error } = await resend.emails.send(options);
1262
+
1263
+ if (error) {
1264
+ throw error;
1265
+ }
1266
+
1267
+ return data;
1268
+ }
1269
+ ```
1270
+
1271
+ Type definitions for all API methods are included in the package.