@agentisend/sdk-node 0.4.0 → 0.5.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.
package/dist/client.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ApiKey, AutomationRun, ReceivedAttachment, ReceivedEmail, ReceivedThread, SentAttachment, RequestLogEntry, EventDefinition, EventFieldType, ApiKeyPermission, BatchItemResult, CreatedApiKey, CreatedWebhookEndpoint, DeadLetter, Deleted, Domain, DomainRegion, DomainSetup, LegacyDomainRegion, Email, EventType, Limit, LimitPeriod, ListEmailsQuery, ListQuery, MetricsQuery, ExplainReport, Page, PreflightReport, ReplayResult, ContactTopic, SendEmailPayload, ServiceStatus, SuppressionBatchItem, AuditEntry, TeamInvite, TeamMember, Topic, BillingPlan, TrustStanding, WebhookEndpoint } from './types.js';
1
+ import type { ApiKey, BroadcastClickedLinksQuery, BroadcastRecipientsQuery, EngagementList, AutomationConnection, AutomationGraphStep, AutomationRun, ReceivedAttachment, ReceivedEmail, ReceivedThread, SentAttachment, RequestLogEntry, EventDefinition, EventFieldType, ApiKeyPermission, BatchItemResult, CreatedApiKey, CreatedWebhookEndpoint, DeadLetter, Deleted, Domain, DomainCapabilities, DomainClaim, DomainRegion, DomainSetup, LegacyDomainRegion, Email, EventType, Limit, LimitPeriod, ListEmailsQuery, ListQuery, MetricsQuery, ExplainReport, Page, PreflightReport, ReplayResult, ContactTopic, SendEmailPayload, TemplateCreatePayload, ServiceStatus, SuppressionBatchItem, AuditEntry, TeamInvite, TeamMember, Topic, BillingPlan, TrustStanding, WebhookEndpoint } from './types.js';
2
2
  export declare const DEFAULT_BASE_URL = "https://api.agentisend.com";
3
3
  export interface FetchResponse {
4
4
  status: number;
@@ -85,10 +85,26 @@ export declare class AgentiSend {
85
85
  }>;
86
86
  get: (id: string) => Promise<Email>;
87
87
  list: (query?: ListEmailsQuery) => Promise<Page<Email>>;
88
- /** Alias of GET /metrics. start_date and end_date name since and until. */
88
+ /**
89
+ * Account-level email metrics in Resend's shape: totals for a range, or
90
+ * rows by period, domain, email or broadcast. since/until answer in the
91
+ * GET /metrics shape instead. Lists are sent comma-separated.
92
+ */
89
93
  metrics: (query?: MetricsQuery) => Promise<Record<string, unknown>>;
90
94
  /** M5.10 — what this email carried, after it was sent. */
91
95
  attachments: (id: string) => Promise<Page<SentAttachment>>;
96
+ /**
97
+ * A link anyone can open to read one sent or received email, with no
98
+ * sign-in. `expires_in` is a duration such as "10m", "2 hours" or "1 day";
99
+ * the default and the most is 48 hours.
100
+ */
101
+ share: (id: string, payload?: {
102
+ expires_in?: string;
103
+ }, options?: RequestOptions) => Promise<{
104
+ object: "email";
105
+ id: string;
106
+ url: string;
107
+ }>;
92
108
  /** Stop a scheduled or queued email. Sent mail is history, not cancellable. */
93
109
  cancel: (id: string, options?: RequestOptions) => Promise<{
94
110
  id: string;
@@ -188,6 +204,17 @@ export declare class AgentiSend {
188
204
  }>;
189
205
  };
190
206
  readonly domains: {
207
+ /** Whether create would accept this name, and the refusal it would give. Creates nothing. */
208
+ check: (name: string) => Promise<{
209
+ name: string;
210
+ can_add: boolean;
211
+ blocklist: "listed" | "clean" | "unknown";
212
+ problems: Array<{
213
+ code: string;
214
+ message: string;
215
+ fix: string;
216
+ }>;
217
+ }>;
191
218
  create: (payload: {
192
219
  name: string;
193
220
  region?: DomainRegion | LegacyDomainRegion;
@@ -197,6 +224,8 @@ export declare class AgentiSend {
197
224
  open_tracking?: boolean;
198
225
  click_tracking?: boolean;
199
226
  tls_mode?: "opportunistic" | "enforced";
227
+ /** Sending defaults to enabled, receiving to disabled. At least one must be enabled. */
228
+ capabilities?: DomainCapabilities;
200
229
  }, options?: RequestOptions) => Promise<Domain>;
201
230
  list: (query?: ListQuery) => Promise<Page<Domain>>;
202
231
  get: (id: string) => Promise<Domain>;
@@ -209,6 +238,8 @@ export declare class AgentiSend {
209
238
  open_tracking?: boolean;
210
239
  tracking_subdomain?: string;
211
240
  tls_mode?: "opportunistic" | "enforced";
241
+ /** Name one or both; the other keeps its value. At least one stays enabled. */
242
+ capabilities?: DomainCapabilities;
212
243
  }, options?: RequestOptions) => Promise<Domain>;
213
244
  delete: (id: string, options?: RequestOptions) => Promise<Deleted>;
214
245
  /**
@@ -231,6 +262,25 @@ export declare class AgentiSend {
231
262
  events: (id: string, query?: ListQuery) => Promise<Page<Record<string, unknown>>>;
232
263
  /** Alias of setup: detects the DNS provider and returns the exact records to add. */
233
264
  connect: (id: string) => Promise<DomainSetup>;
265
+ /**
266
+ * Start a claim for a domain another account has verified. Publish the TXT
267
+ * `record` it returns, then `verifyClaim`. Nothing moves until the safety
268
+ * checks pass.
269
+ */
270
+ claim: (payload: {
271
+ name: string;
272
+ region?: DomainRegion | LegacyDomainRegion;
273
+ tracking?: boolean;
274
+ tracking_subdomain?: string;
275
+ return_path_subdomain?: string;
276
+ open_tracking?: boolean;
277
+ click_tracking?: boolean;
278
+ tls_mode?: "opportunistic" | "enforced";
279
+ }, options?: RequestOptions) => Promise<DomainClaim>;
280
+ /** The latest claim for the placeholder domain a claim created. Poll it until `completed`. */
281
+ getClaim: (domainId: string) => Promise<DomainClaim>;
282
+ /** Check the claim's TXT record and, when it is there, run the ownership checks and move the domain. */
283
+ verifyClaim: (domainId: string, options?: RequestOptions) => Promise<DomainClaim>;
234
284
  };
235
285
  readonly webhooks: {
236
286
  create: (payload: {
@@ -273,6 +323,24 @@ export declare class AgentiSend {
273
323
  rotated_at: string;
274
324
  previous_secret_expires_at: string;
275
325
  }>;
326
+ /** The same rotation on Resend's path. */
327
+ rotateSigningSecret: (id: string, options?: RequestOptions) => Promise<Record<string, unknown>>;
328
+ /** What was sent to this endpoint: pending, attempting, success or failed. */
329
+ listEvents: (id: string, query?: {
330
+ limit?: number;
331
+ after?: string;
332
+ }) => Promise<Page<Record<string, unknown>>>;
333
+ getEvent: (id: string, eventId: string) => Promise<Record<string, unknown>>;
334
+ /** Each attempt to deliver one event, with the status code and body the endpoint answered. */
335
+ listEventAttempts: (id: string, eventId: string, query?: {
336
+ limit?: number;
337
+ after?: string;
338
+ }) => Promise<Page<Record<string, unknown>>>;
339
+ /** Send one event to the endpoint again, as a new delivery marked as a replay. */
340
+ replayEvent: (id: string, eventId: string, options?: RequestOptions) => Promise<{
341
+ object: string;
342
+ id: string;
343
+ }>;
276
344
  };
277
345
  readonly limits: {
278
346
  list: (query?: ListQuery) => Promise<Page<Limit>>;
@@ -368,6 +436,17 @@ export declare class AgentiSend {
368
436
  }, options?: RequestOptions) => Promise<{
369
437
  fired: number;
370
438
  }>;
439
+ /** Resend's form: one event for one contact, by contact_id or email. */
440
+ send: (payload: {
441
+ event: string;
442
+ contact_id?: string;
443
+ email?: string;
444
+ payload?: Record<string, unknown>;
445
+ }, options?: RequestOptions) => Promise<{
446
+ object: "event";
447
+ event: string;
448
+ fired: number;
449
+ }>;
371
450
  list: (query?: ListQuery) => Promise<Page<EventDefinition>>;
372
451
  get: (id: string) => Promise<EventDefinition>;
373
452
  update: (id: string, payload: {
@@ -379,19 +458,53 @@ export declare class AgentiSend {
379
458
  };
380
459
  /** M5.6 — what an automation actually did, after it did it. */
381
460
  readonly automations: {
461
+ /**
462
+ * Linear: `{ name, trigger, steps }` with steps of kind email, webhook or
463
+ * ab_split. Graph (Resend's shape): `{ name, status?, steps, connections }`
464
+ * with steps `{ key, type, config }`.
465
+ */
382
466
  create: (payload: {
383
467
  name: string;
468
+ status?: "enabled" | "disabled";
384
469
  trigger: Record<string, unknown>;
385
470
  steps: Record<string, unknown>[];
471
+ } | {
472
+ name: string;
473
+ status?: "enabled" | "disabled";
474
+ steps: AutomationGraphStep[];
475
+ connections: AutomationConnection[];
386
476
  }, options?: RequestOptions) => Promise<Record<string, unknown>>;
387
- list: (query?: ListQuery) => Promise<Page<Record<string, unknown>>>;
477
+ list: (query?: ListQuery & {
478
+ status?: "enabled" | "disabled";
479
+ }) => Promise<Page<Record<string, unknown>>>;
388
480
  get: (id: string) => Promise<Record<string, unknown>>;
389
481
  update: (id: string, payload: Record<string, unknown>, options?: RequestOptions) => Promise<Record<string, unknown>>;
390
482
  enable: (id: string, options?: RequestOptions) => Promise<Record<string, unknown>>;
391
483
  disable: (id: string, options?: RequestOptions) => Promise<Record<string, unknown>>;
392
484
  versions: (id: string) => Promise<Page<Record<string, unknown>>>;
485
+ /** Copy an automation, disabled. Edit the copy, enable it, then stop the original. */
486
+ duplicate: (id: string, options?: RequestOptions) => Promise<Record<string, unknown>>;
487
+ /**
488
+ * No new runs start; runs in progress finish as they started.
489
+ * `cancelRuns: true` cancels those as well.
490
+ */
491
+ stop: (id: string, query?: {
492
+ cancelRuns?: boolean;
493
+ }, options?: RequestOptions) => Promise<{
494
+ object: "automation";
495
+ id: string;
496
+ status: "disabled";
497
+ runs_cancelled: number;
498
+ }>;
499
+ /** Delete an automation; runs in progress are cancelled first. */
500
+ remove: (id: string, options?: RequestOptions) => Promise<{
501
+ object: "automation";
502
+ id: string;
503
+ deleted: true;
504
+ }>;
505
+ /** `status` is one value or a comma-separated list. */
393
506
  runs: (automationId: string, query?: ListQuery & {
394
- status?: "running" | "succeeded" | "failed";
507
+ status?: AutomationRun["status"] | string;
395
508
  }) => Promise<Page<AutomationRun>>;
396
509
  run: (automationId: string, runId: string) => Promise<AutomationRun>;
397
510
  };
@@ -426,17 +539,38 @@ export declare class AgentiSend {
426
539
  }, options?: RequestOptions) => Promise<{
427
540
  data: Record<string, unknown>[];
428
541
  }>;
429
- /** CSV in `csv`. Finishes in this response. `on_conflict` defaults to skip. */
542
+ /**
543
+ * CSV in `csv`. Finishes in this response; read it back with imports.get.
544
+ * `column_map` is Resend's, a field on the left and a CSV column on the right.
545
+ * `on_conflict` defaults to skip.
546
+ */
430
547
  importCsv: (payload: {
431
548
  csv: string;
432
- column_map?: Record<string, string>;
549
+ column_map?: Record<string, unknown>;
433
550
  on_conflict?: "skip" | "upsert";
551
+ segments?: Array<{
552
+ id: string;
553
+ }>;
554
+ topics?: Array<{
555
+ id: string;
556
+ subscription: "opt_in" | "opt_out";
557
+ }>;
434
558
  }, options?: RequestOptions) => Promise<Record<string, unknown>>;
435
- /** Segments whose rules include this contact. The id may be an email. */
559
+ /** Past contact imports, newest first. */
560
+ imports: {
561
+ list: (query?: {
562
+ status?: "queued" | "in_progress" | "completed" | "failed";
563
+ limit?: number;
564
+ after?: string;
565
+ before?: string;
566
+ }) => Promise<Page<Record<string, unknown>>>;
567
+ get: (id: string) => Promise<Record<string, unknown>>;
568
+ };
569
+ /** Segments this contact is in: rule matches and direct additions. The id may be an email. */
436
570
  segments: (id: string) => Promise<Page<Record<string, unknown>>>;
437
- /** Refused: membership is the segment's rules. Names PATCH /segments/:id. */
571
+ /** Add a contact to a segment. It stays in until removed, whatever the rules say. */
438
572
  addSegment: (id: string, segmentId: string, options?: RequestOptions) => Promise<Record<string, unknown>>;
439
- /** Refused: membership is the segment's rules. Names PATCH /segments/:id. */
573
+ /** Remove a contact that was added to a segment. One in it only by its rules is refused. */
440
574
  removeSegment: (id: string, segmentId: string, options?: RequestOptions) => Promise<Record<string, unknown>>;
441
575
  /** Lift a marketing unsubscribe after the person opts back in. */
442
576
  resubscribe: (id: string, payload: {
@@ -444,16 +578,49 @@ export declare class AgentiSend {
444
578
  consent_at: string;
445
579
  }, options?: RequestOptions) => Promise<Record<string, unknown>>;
446
580
  };
447
- /** Property names and types already stored on the account. */
581
+ /** Declared properties with their fallback_value, and the names contacts already hold. */
448
582
  readonly contactProperties: {
449
583
  list: () => Promise<Page<Record<string, unknown>>>;
450
584
  get: (id: string) => Promise<Record<string, unknown>>;
585
+ /** Declare a property. type is string or number; fallback_value fills in for a contact with none. */
586
+ create: (payload: {
587
+ key: string;
588
+ type: "string" | "number";
589
+ fallback_value?: string | number | null;
590
+ }, options?: RequestOptions) => Promise<{
591
+ object: "contact_property";
592
+ id: string;
593
+ }>;
594
+ /** Change the fallback_value. The key and type cannot change. */
595
+ update: (id: string, payload: {
596
+ fallback_value: string | number | null;
597
+ }, options?: RequestOptions) => Promise<{
598
+ object: "contact_property";
599
+ id: string;
600
+ }>;
601
+ /** Remove a declared property. Values contacts hold under its key stay on them. */
602
+ delete: (id: string, options?: RequestOptions) => Promise<{
603
+ object: "contact_property";
604
+ id: string;
605
+ deleted: true;
606
+ }>;
451
607
  };
452
608
  /**
453
609
  * The same contact list, at the paths the official SDK uses when a call
454
610
  * names an audience. This account has one contact list.
455
611
  */
456
612
  readonly audiences: {
613
+ create: (payload: {
614
+ name: string;
615
+ }, options?: RequestOptions) => Promise<Record<string, unknown>>;
616
+ list: (query?: ListQuery) => Promise<Page<Record<string, unknown>>>;
617
+ get: (id: string) => Promise<Record<string, unknown>>;
618
+ delete: (id: string, options?: RequestOptions) => Promise<Deleted>;
619
+ /** The account contact list. An audience id on this path does not select a second list. */
620
+ contacts: (id: string, query?: ListQuery & {
621
+ email?: string;
622
+ }) => Promise<Page<Record<string, unknown>>>;
623
+ members: (id: string) => Promise<Page<Record<string, unknown>>>;
457
624
  createContact: (audienceId: string, payload: {
458
625
  email: string;
459
626
  properties?: Record<string, unknown>;
@@ -467,6 +634,12 @@ export declare class AgentiSend {
467
634
  };
468
635
  readonly broadcasts: {
469
636
  create: (payload: Record<string, unknown>, options?: RequestOptions) => Promise<Record<string, unknown>>;
637
+ /** Delete a draft. A scheduled or sent broadcast is refused; archive it instead. */
638
+ delete: (id: string, options?: RequestOptions) => Promise<{
639
+ object: "broadcast";
640
+ id: string;
641
+ deleted: boolean;
642
+ }>;
470
643
  list: (query?: ListQuery) => Promise<Page<Record<string, unknown>>>;
471
644
  get: (id: string) => Promise<Record<string, unknown>>;
472
645
  /** Sent, delivered, opened, clicked, bounced, complained and unsubscribed. A test send is not included. */
@@ -475,6 +648,7 @@ export declare class AgentiSend {
475
648
  preview: (id: string) => Promise<{
476
649
  subject: string;
477
650
  html: string;
651
+ preview_text: string | null;
478
652
  }>;
479
653
  update: (id: string, payload: Record<string, unknown>, options?: RequestOptions) => Promise<Record<string, unknown>>;
480
654
  /**
@@ -489,16 +663,29 @@ export declare class AgentiSend {
489
663
  /** Archive, not delete: a sent broadcast is history worth keeping (F14). */
490
664
  archive: (id: string, options?: RequestOptions) => Promise<Record<string, unknown>>;
491
665
  messages: (id: string, query?: ListQuery) => Promise<Page<Record<string, unknown>>>;
666
+ /**
667
+ * Who the broadcast reached and what they did, for one event `type`
668
+ * (Resend: list-broadcast-recipients). Rows page with opaque `id` cursors
669
+ * through `after` and `before`.
670
+ */
671
+ recipients: (id: string, query: BroadcastRecipientsQuery) => Promise<EngagementList<Record<string, unknown>>>;
672
+ /** Every link clicked in the broadcast, most clicked first, with total and unique clicks. */
673
+ clickedLinks: (id: string, query?: BroadcastClickedLinksQuery) => Promise<EngagementList<Record<string, unknown>>>;
492
674
  /** Cancel a scheduled broadcast, or stop one that is still sending. Mail already handed off is not pulled back. A scheduled broadcast returns to draft. */
493
675
  cancel: (id: string, options?: RequestOptions) => Promise<Record<string, unknown>>;
676
+ /** Copy a broadcast into a new draft: the message, segment, reply_to, preview_text and topic_id. No schedule, sends or history. */
677
+ duplicate: (id: string, payload?: {
678
+ name?: string;
679
+ }, options?: RequestOptions) => Promise<Record<string, unknown>>;
494
680
  };
681
+ /**
682
+ * Templates. Wherever a method takes `id`, the template's alias works too
683
+ * (Resend: "The Template ID or alias"). Editing a published template opens
684
+ * a draft from its live version; the live version keeps sending until
685
+ * `publish`.
686
+ */
495
687
  readonly templates: {
496
- create: (payload: {
497
- name: string;
498
- subject: string;
499
- content: unknown;
500
- variables?: unknown[];
501
- }, options?: RequestOptions) => Promise<Record<string, unknown>>;
688
+ create: (payload: TemplateCreatePayload, options?: RequestOptions) => Promise<Record<string, unknown>>;
502
689
  list: (query?: ListQuery) => Promise<Page<Record<string, unknown>>>;
503
690
  get: (id: string) => Promise<Record<string, unknown>>;
504
691
  update: (id: string, payload: Record<string, unknown>, options?: RequestOptions) => Promise<Record<string, unknown>>;
@@ -568,11 +755,6 @@ export declare class AgentiSend {
568
755
  get: (id: string) => Promise<Record<string, unknown>>;
569
756
  update: (id: string, payload: Record<string, unknown>, options?: RequestOptions) => Promise<Record<string, unknown>>;
570
757
  delete: (id: string, options?: RequestOptions) => Promise<Deleted>;
571
- /** The account contact list. An audience id on this path does not select a second list. */
572
- contacts: (id: string, query?: ListQuery & {
573
- email?: string;
574
- }) => Promise<Page<Record<string, unknown>>>;
575
- members: (id: string) => Promise<Page<Record<string, unknown>>>;
576
758
  };
577
759
  /**
578
760
  * M4.9 — this account's own history. `action` takes a family (`api_key`) or
@@ -665,7 +847,7 @@ export declare class AgentiSend {
665
847
  */
666
848
  readonly dnsCheck: (domain: string) => Promise<Record<string, unknown>>;
667
849
  /** Send, delivery and engagement figures with a daily series, over a window. */
668
- readonly metrics: (query?: MetricsQuery & {
850
+ readonly metrics: (query?: Pick<MetricsQuery, "since" | "until" | "start_date" | "end_date"> & {
669
851
  group_by?: string;
670
852
  event?: "sent" | "delivered" | "bounced" | "complained" | "opened" | "clicked";
671
853
  domain?: string;
package/dist/client.js CHANGED
@@ -9,6 +9,10 @@ export const DEFAULT_BASE_URL = 'https://api.agentisend.com';
9
9
  export function idempotencyKey(action, subject) {
10
10
  return `${action}/${String(subject)}`;
11
11
  }
12
+ /** Resend's list parameters are comma-separated on the wire; arrays join. */
13
+ function joinLists(query) {
14
+ return Object.fromEntries(Object.entries(query).map(([key, value]) => [key, Array.isArray(value) ? value.join(',') : value]));
15
+ }
12
16
  function buildQuery(query) {
13
17
  if (!query)
14
18
  return '';
@@ -177,14 +181,29 @@ export class AgentiSend {
177
181
  path: '/emails',
178
182
  query: query,
179
183
  }),
180
- /** Alias of GET /metrics. start_date and end_date name since and until. */
184
+ /**
185
+ * Account-level email metrics in Resend's shape: totals for a range, or
186
+ * rows by period, domain, email or broadcast. since/until answer in the
187
+ * GET /metrics shape instead. Lists are sent comma-separated.
188
+ */
181
189
  metrics: (query = {}) => this.request({
182
190
  method: 'GET',
183
191
  path: '/emails/metrics',
184
- query: query,
192
+ query: joinLists(query),
185
193
  }),
186
194
  /** M5.10 — what this email carried, after it was sent. */
187
195
  attachments: (id) => this.request({ method: 'GET', path: `/emails/${id}/attachments` }),
196
+ /**
197
+ * A link anyone can open to read one sent or received email, with no
198
+ * sign-in. `expires_in` is a duration such as "10m", "2 hours" or "1 day";
199
+ * the default and the most is 48 hours.
200
+ */
201
+ share: (id, payload = {}, options) => this.request({
202
+ method: 'POST',
203
+ path: `/emails/${id}/share`,
204
+ body: payload,
205
+ ...(options ? { options } : {}),
206
+ }),
188
207
  /** Stop a scheduled or queued email. Sent mail is history, not cancellable. */
189
208
  cancel: (id, options) => this.request({
190
209
  method: 'POST',
@@ -280,6 +299,8 @@ export class AgentiSend {
280
299
  }),
281
300
  };
282
301
  domains = {
302
+ /** Whether create would accept this name, and the refusal it would give. Creates nothing. */
303
+ check: (name) => this.request({ method: 'GET', path: '/domains/check', query: { name } }),
283
304
  create: (payload, options) => this.request({ method: 'POST', path: '/domains', body: payload, ...(options ? { options } : {}) }),
284
305
  list: (query = {}) => this.request({
285
306
  method: 'GET',
@@ -316,6 +337,20 @@ export class AgentiSend {
316
337
  }),
317
338
  /** Alias of setup: detects the DNS provider and returns the exact records to add. */
318
339
  connect: (id) => this.request({ method: 'GET', path: `/domains/${id}/connect` }),
340
+ /**
341
+ * Start a claim for a domain another account has verified. Publish the TXT
342
+ * `record` it returns, then `verifyClaim`. Nothing moves until the safety
343
+ * checks pass.
344
+ */
345
+ claim: (payload, options) => this.request({ method: 'POST', path: '/domains/claim', body: payload, ...(options ? { options } : {}) }),
346
+ /** The latest claim for the placeholder domain a claim created. Poll it until `completed`. */
347
+ getClaim: (domainId) => this.request({ method: 'GET', path: `/domains/${domainId}/claim` }),
348
+ /** Check the claim's TXT record and, when it is there, run the ownership checks and move the domain. */
349
+ verifyClaim: (domainId, options) => this.request({
350
+ method: 'POST',
351
+ path: `/domains/${domainId}/claim/verify`,
352
+ ...(options ? { options } : {}),
353
+ }),
319
354
  };
320
355
  webhooks = {
321
356
  create: (payload, options) => this.request({ method: 'POST', path: '/webhooks', body: payload, ...(options ? { options } : {}) }),
@@ -358,6 +393,19 @@ export class AgentiSend {
358
393
  path: `/webhooks/${id}/rotate-secret`,
359
394
  ...(options ? { options } : {}),
360
395
  }),
396
+ /** The same rotation on Resend's path. */
397
+ rotateSigningSecret: (id, options) => this.request({ method: 'POST', path: `/webhooks/${id}/signing-secret/rotate`, ...(options ? { options } : {}) }),
398
+ /** What was sent to this endpoint: pending, attempting, success or failed. */
399
+ listEvents: (id, query = {}) => this.request({ method: 'GET', path: `/webhooks/${id}/events`, query: query }),
400
+ getEvent: (id, eventId) => this.request({ method: 'GET', path: `/webhooks/${id}/events/${eventId}` }),
401
+ /** Each attempt to deliver one event, with the status code and body the endpoint answered. */
402
+ listEventAttempts: (id, eventId, query = {}) => this.request({
403
+ method: 'GET',
404
+ path: `/webhooks/${id}/events/${eventId}/attempts`,
405
+ query: query,
406
+ }),
407
+ /** Send one event to the endpoint again, as a new delivery marked as a replay. */
408
+ replayEvent: (id, eventId, options) => this.request({ method: 'POST', path: `/webhooks/${id}/events/${eventId}/replay`, ...(options ? { options } : {}) }),
361
409
  };
362
410
  limits = {
363
411
  list: (query = {}) => this.request({
@@ -451,6 +499,8 @@ export class AgentiSend {
451
499
  */
452
500
  events = {
453
501
  ingest: (payload, options) => this.request({ method: 'POST', path: '/events', body: payload, ...(options ? { options } : {}) }),
502
+ /** Resend's form: one event for one contact, by contact_id or email. */
503
+ send: (payload, options) => this.request({ method: 'POST', path: '/events/send', body: payload, ...(options ? { options } : {}) }),
454
504
  list: (query = {}) => this.request({
455
505
  method: 'GET',
456
506
  path: '/events',
@@ -467,6 +517,11 @@ export class AgentiSend {
467
517
  };
468
518
  /** M5.6 — what an automation actually did, after it did it. */
469
519
  automations = {
520
+ /**
521
+ * Linear: `{ name, trigger, steps }` with steps of kind email, webhook or
522
+ * ab_split. Graph (Resend's shape): `{ name, status?, steps, connections }`
523
+ * with steps `{ key, type, config }`.
524
+ */
470
525
  create: (payload, options) => this.request({ method: 'POST', path: '/automations', body: payload, ...(options ? { options } : {}) }),
471
526
  list: (query = {}) => this.request({
472
527
  method: 'GET',
@@ -478,6 +533,21 @@ export class AgentiSend {
478
533
  enable: (id, options) => this.request({ method: 'POST', path: `/automations/${id}/enable`, ...(options ? { options } : {}) }),
479
534
  disable: (id, options) => this.request({ method: 'POST', path: `/automations/${id}/disable`, ...(options ? { options } : {}) }),
480
535
  versions: (id) => this.request({ method: 'GET', path: `/automations/${id}/versions` }),
536
+ /** Copy an automation, disabled. Edit the copy, enable it, then stop the original. */
537
+ duplicate: (id, options) => this.request({ method: 'POST', path: `/automations/${id}/duplicate`, ...(options ? { options } : {}) }),
538
+ /**
539
+ * No new runs start; runs in progress finish as they started.
540
+ * `cancelRuns: true` cancels those as well.
541
+ */
542
+ stop: (id, query = {}, options) => this.request({
543
+ method: 'POST',
544
+ path: `/automations/${id}/stop`,
545
+ ...(query.cancelRuns !== undefined ? { query: { cancel_runs: String(query.cancelRuns) } } : {}),
546
+ ...(options ? { options } : {}),
547
+ }),
548
+ /** Delete an automation; runs in progress are cancelled first. */
549
+ remove: (id, options) => this.request({ method: 'DELETE', path: `/automations/${id}`, ...(options ? { options } : {}) }),
550
+ /** `status` is one value or a comma-separated list. */
481
551
  runs: (automationId, query = {}) => this.request({
482
552
  method: 'GET',
483
553
  path: `/automations/${automationId}/runs`,
@@ -512,17 +582,26 @@ export class AgentiSend {
512
582
  }),
513
583
  /** Up to 1,000 contacts. Each item succeeds or fails on its own. */
514
584
  batch: (payload, options) => this.request({ method: 'POST', path: '/contacts/batch', body: payload, ...(options ? { options } : {}) }),
515
- /** CSV in `csv`. Finishes in this response. `on_conflict` defaults to skip. */
585
+ /**
586
+ * CSV in `csv`. Finishes in this response; read it back with imports.get.
587
+ * `column_map` is Resend's, a field on the left and a CSV column on the right.
588
+ * `on_conflict` defaults to skip.
589
+ */
516
590
  importCsv: (payload, options) => this.request({ method: 'POST', path: '/contacts/imports', body: payload, ...(options ? { options } : {}) }),
517
- /** Segments whose rules include this contact. The id may be an email. */
591
+ /** Past contact imports, newest first. */
592
+ imports: {
593
+ list: (query) => this.request({ method: 'GET', path: '/contacts/imports', ...(query ? { query } : {}) }),
594
+ get: (id) => this.request({ method: 'GET', path: `/contacts/imports/${id}` }),
595
+ },
596
+ /** Segments this contact is in: rule matches and direct additions. The id may be an email. */
518
597
  segments: (id) => this.request({ method: 'GET', path: `/contacts/${id}/segments` }),
519
- /** Refused: membership is the segment's rules. Names PATCH /segments/:id. */
598
+ /** Add a contact to a segment. It stays in until removed, whatever the rules say. */
520
599
  addSegment: (id, segmentId, options) => this.request({
521
600
  method: 'POST',
522
601
  path: `/contacts/${id}/segments/${segmentId}`,
523
602
  ...(options ? { options } : {}),
524
603
  }),
525
- /** Refused: membership is the segment's rules. Names PATCH /segments/:id. */
604
+ /** Remove a contact that was added to a segment. One in it only by its rules is refused. */
526
605
  removeSegment: (id, segmentId, options) => this.request({
527
606
  method: 'DELETE',
528
607
  path: `/contacts/${id}/segments/${segmentId}`,
@@ -536,16 +615,38 @@ export class AgentiSend {
536
615
  ...(options ? { options } : {}),
537
616
  }),
538
617
  };
539
- /** Property names and types already stored on the account. */
618
+ /** Declared properties with their fallback_value, and the names contacts already hold. */
540
619
  contactProperties = {
541
620
  list: () => this.request({ method: 'GET', path: '/contact-properties' }),
542
621
  get: (id) => this.request({ method: 'GET', path: `/contact-properties/${id}` }),
622
+ /** Declare a property. type is string or number; fallback_value fills in for a contact with none. */
623
+ create: (payload, options) => this.request({ method: 'POST', path: '/contact-properties', body: payload, ...(options ? { options } : {}) }),
624
+ /** Change the fallback_value. The key and type cannot change. */
625
+ update: (id, payload, options) => this.request({
626
+ method: 'PATCH',
627
+ path: `/contact-properties/${id}`,
628
+ body: payload,
629
+ ...(options ? { options } : {}),
630
+ }),
631
+ /** Remove a declared property. Values contacts hold under its key stay on them. */
632
+ delete: (id, options) => this.request({ method: 'DELETE', path: `/contact-properties/${id}`, ...(options ? { options } : {}) }),
543
633
  };
544
634
  /**
545
635
  * The same contact list, at the paths the official SDK uses when a call
546
636
  * names an audience. This account has one contact list.
547
637
  */
548
638
  audiences = {
639
+ create: (payload, options) => this.request({ method: 'POST', path: '/audiences', body: payload, ...(options ? { options } : {}) }),
640
+ list: (query = {}) => this.request({ method: 'GET', path: '/audiences', query: query }),
641
+ get: (id) => this.request({ method: 'GET', path: `/audiences/${id}` }),
642
+ delete: (id, options) => this.request({ method: 'DELETE', path: `/audiences/${id}`, ...(options ? { options } : {}) }),
643
+ /** The account contact list. An audience id on this path does not select a second list. */
644
+ contacts: (id, query = {}) => this.request({
645
+ method: 'GET',
646
+ path: `/segments/${id}/contacts`,
647
+ query: query,
648
+ }),
649
+ members: (id) => this.request({ method: 'GET', path: `/segments/${id}/members` }),
549
650
  createContact: (audienceId, payload, options) => this.request({
550
651
  method: 'POST',
551
652
  path: `/audiences/${audienceId}/contacts`,
@@ -572,6 +673,8 @@ export class AgentiSend {
572
673
  };
573
674
  broadcasts = {
574
675
  create: (payload, options) => this.request({ method: 'POST', path: '/broadcasts', body: payload, ...(options ? { options } : {}) }),
676
+ /** Delete a draft. A scheduled or sent broadcast is refused; archive it instead. */
677
+ delete: (id, options) => this.request({ method: 'DELETE', path: `/broadcasts/${id}`, ...(options ? { options } : {}) }),
575
678
  list: (query = {}) => this.request({
576
679
  method: 'GET',
577
680
  path: '/broadcasts',
@@ -602,13 +705,42 @@ export class AgentiSend {
602
705
  path: `/broadcasts/${id}/messages`,
603
706
  query: query,
604
707
  }),
708
+ /**
709
+ * Who the broadcast reached and what they did, for one event `type`
710
+ * (Resend: list-broadcast-recipients). Rows page with opaque `id` cursors
711
+ * through `after` and `before`.
712
+ */
713
+ recipients: (id, query) => this.request({
714
+ method: 'GET',
715
+ path: `/broadcasts/${id}/recipients`,
716
+ query: query,
717
+ }),
718
+ /** Every link clicked in the broadcast, most clicked first, with total and unique clicks. */
719
+ clickedLinks: (id, query = {}) => this.request({
720
+ method: 'GET',
721
+ path: `/broadcasts/${id}/clicked-links`,
722
+ query: query,
723
+ }),
605
724
  /** Cancel a scheduled broadcast, or stop one that is still sending. Mail already handed off is not pulled back. A scheduled broadcast returns to draft. */
606
725
  cancel: (id, options) => this.request({
607
726
  method: 'POST',
608
727
  path: `/broadcasts/${id}/cancel`,
609
728
  ...(options ? { options } : {}),
610
729
  }),
730
+ /** Copy a broadcast into a new draft: the message, segment, reply_to, preview_text and topic_id. No schedule, sends or history. */
731
+ duplicate: (id, payload = {}, options) => this.request({
732
+ method: 'POST',
733
+ path: `/broadcasts/${id}/duplicate`,
734
+ body: payload,
735
+ ...(options ? { options } : {}),
736
+ }),
611
737
  };
738
+ /**
739
+ * Templates. Wherever a method takes `id`, the template's alias works too
740
+ * (Resend: "The Template ID or alias"). Editing a published template opens
741
+ * a draft from its live version; the live version keeps sending until
742
+ * `publish`.
743
+ */
612
744
  templates = {
613
745
  create: (payload, options) => this.request({ method: 'POST', path: '/templates', body: payload, ...(options ? { options } : {}) }),
614
746
  list: (query = {}) => this.request({
@@ -700,13 +832,6 @@ export class AgentiSend {
700
832
  get: (id) => this.request({ method: 'GET', path: `/segments/${id}` }),
701
833
  update: (id, payload, options) => this.request({ method: 'PATCH', path: `/segments/${id}`, body: payload, ...(options ? { options } : {}) }),
702
834
  delete: (id, options) => this.request({ method: 'DELETE', path: `/segments/${id}`, ...(options ? { options } : {}) }),
703
- /** The account contact list. An audience id on this path does not select a second list. */
704
- contacts: (id, query = {}) => this.request({
705
- method: 'GET',
706
- path: `/segments/${id}/contacts`,
707
- query: query,
708
- }),
709
- members: (id) => this.request({ method: 'GET', path: `/segments/${id}/members` }),
710
835
  };
711
836
  /**
712
837
  * M4.9 — this account's own history. `action` takes a family (`api_key`) or