@agentisend/sdk-node 0.1.0 → 0.4.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.
package/dist/client.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { AgentiSendError, AgentiSendTransportError, } from './errors.js';
2
+ import { SDK_VERSION } from './version.js';
2
3
  export const DEFAULT_BASE_URL = 'https://api.agentisend.com';
3
4
  /**
4
5
  * Build an idempotency key in the shape that debugs well: `<what>/<which>`,
@@ -78,12 +79,13 @@ export class AgentiSend {
78
79
  }
79
80
  this.fetchImpl = resolved;
80
81
  this.timeoutMs = options.timeoutMs ?? 30_000;
81
- this.userAgent = options.userAgent ?? 'agentisend-node';
82
+ // DX-14: the version travels, so support can tell 0.2.0 from 0.3.0.
83
+ this.userAgent = options.userAgent ?? `agentisend-node/${SDK_VERSION} node/${process.versions.node}`;
82
84
  }
83
- async request(raw) {
85
+ send(raw, accept) {
84
86
  const headers = {
85
87
  authorization: `Bearer ${this.apiKey}`,
86
- accept: 'application/json',
88
+ accept,
87
89
  'user-agent': this.userAgent,
88
90
  };
89
91
  if (raw.body !== undefined)
@@ -91,14 +93,19 @@ export class AgentiSend {
91
93
  if (raw.options?.idempotencyKey) {
92
94
  headers['idempotency-key'] = raw.options.idempotencyKey;
93
95
  }
94
- const response = await this.fetchImpl(`${this.baseUrl}${raw.path}${buildQuery(raw.query)}`, {
96
+ if (raw.options?.headers) {
97
+ Object.assign(headers, raw.options.headers);
98
+ }
99
+ return this.fetchImpl(`${this.baseUrl}${raw.path}${buildQuery(raw.query)}`, {
95
100
  method: raw.method,
96
101
  headers,
97
102
  ...(raw.body !== undefined ? { body: JSON.stringify(raw.body) } : {}),
98
103
  signal: raw.options?.signal ?? AbortSignal.timeout(this.timeoutMs),
99
104
  });
105
+ }
106
+ async request(raw) {
107
+ const response = await this.send(raw, 'application/json');
100
108
  const text = await response.text();
101
- const requestId = response.headers.get('x-request-id') ?? undefined;
102
109
  if (response.status === 204 || text.length === 0) {
103
110
  if (response.status >= 400) {
104
111
  throw new AgentiSendTransportError(`Request failed with ${response.status} and an empty body`, response.status, '');
@@ -112,19 +119,48 @@ export class AgentiSend {
112
119
  catch {
113
120
  throw new AgentiSendTransportError(`Response was not JSON (${response.status})`, response.status, text.slice(0, 500));
114
121
  }
122
+ if (response.status >= 400)
123
+ this.fail(response, parsed, text);
124
+ return parsed;
125
+ }
126
+ /**
127
+ * A response that is not JSON: an attachment, an .eml, the CSV export. A
128
+ * refusal still arrives as the JSON error envelope and throws the same
129
+ * AgentiSendError that request() throws.
130
+ */
131
+ async requestBytes(raw) {
132
+ const response = await this.send(raw, '*/*');
115
133
  if (response.status >= 400) {
116
- if (!isErrorPayload(parsed)) {
117
- throw new AgentiSendTransportError(`Unexpected error shape (${response.status})`, response.status, text.slice(0, 500));
134
+ const text = await response.text();
135
+ let parsed;
136
+ try {
137
+ parsed = JSON.parse(text);
138
+ }
139
+ catch {
140
+ throw new AgentiSendTransportError(`Request failed with ${response.status}`, response.status, text.slice(0, 500));
118
141
  }
119
- const retryAfter = response.headers.get('retry-after');
120
- const rateLimit = readRateLimit(response);
121
- throw new AgentiSendError(parsed.error, response.status, {
122
- ...(retryAfter ? { retryAfterSeconds: Number(retryAfter) } : {}),
123
- ...(requestId ? { requestId } : {}),
124
- ...(rateLimit ? { rateLimit } : {}),
125
- });
142
+ this.fail(response, parsed, text);
126
143
  }
127
- return parsed;
144
+ if (response.arrayBuffer)
145
+ return new Uint8Array(await response.arrayBuffer());
146
+ return new TextEncoder().encode(await response.text());
147
+ }
148
+ /** The same download, decoded as UTF-8: an .eml, raw MIME, a CSV. */
149
+ async requestText(raw) {
150
+ return new TextDecoder().decode(await this.requestBytes(raw));
151
+ }
152
+ fail(response, parsed, text) {
153
+ if (!isErrorPayload(parsed)) {
154
+ throw new AgentiSendTransportError(`Unexpected error shape (${response.status})`, response.status, text.slice(0, 500));
155
+ }
156
+ const requestId = response.headers.get('x-request-id') ?? undefined;
157
+ const retryAfter = response.headers.get('retry-after');
158
+ const rateLimit = readRateLimit(response);
159
+ throw new AgentiSendError(parsed.error, response.status, {
160
+ ...(retryAfter ? { retryAfterSeconds: Number(retryAfter) } : {}),
161
+ ...(requestId ? { requestId } : {}),
162
+ ...(rateLimit ? { rateLimit } : {}),
163
+ });
128
164
  }
129
165
  emails = {
130
166
  send: (payload, options) => this.request({ method: 'POST', path: '/emails', body: payload, ...(options ? { options } : {}) }),
@@ -141,6 +177,12 @@ export class AgentiSend {
141
177
  path: '/emails',
142
178
  query: query,
143
179
  }),
180
+ /** Alias of GET /metrics. start_date and end_date name since and until. */
181
+ metrics: (query = {}) => this.request({
182
+ method: 'GET',
183
+ path: '/emails/metrics',
184
+ query: query,
185
+ }),
144
186
  /** M5.10 — what this email carried, after it was sent. */
145
187
  attachments: (id) => this.request({ method: 'GET', path: `/emails/${id}/attachments` }),
146
188
  /** Stop a scheduled or queued email. Sent mail is history, not cancellable. */
@@ -149,11 +191,20 @@ export class AgentiSend {
149
191
  path: `/emails/${id}/cancel`,
150
192
  ...(options ? { options } : {}),
151
193
  }),
194
+ /** Delete a sent email and its events for good. A scheduled one must be cancelled first. */
195
+ remove: (id, options) => this.request({
196
+ method: 'DELETE',
197
+ path: `/emails/${id}`,
198
+ ...(options ? { options } : {}),
199
+ }),
152
200
  /** Move an email to a new time. Works from scheduled AND canceled. */
153
201
  reschedule: (id, scheduledAt, options) => this.request({
154
202
  method: 'POST',
155
203
  path: `/emails/${id}/reschedule`,
156
- body: { scheduled_at: scheduledAt },
204
+ body: {
205
+ scheduled_at: scheduledAt,
206
+ ...(options?.timezone !== undefined ? { timezone: options.timezone } : {}),
207
+ },
157
208
  ...(options ? { options } : {}),
158
209
  }),
159
210
  /**
@@ -164,6 +215,33 @@ export class AgentiSend {
164
215
  explain: (id) => this.request({ method: 'GET', path: `/emails/${id}/explain` }),
165
216
  /** Run every gate without sending or spending. Free, always. */
166
217
  preflight: (payload) => this.request({ method: 'POST', path: '/emails/preflight', body: payload }),
218
+ /** Deliverability lint without sending: a 0-100 placement score and every finding with its fix. */
219
+ lint: (payload) => this.request({ method: 'POST', path: '/emails/lint', body: payload }),
220
+ /** Every event recorded for one message, oldest first. */
221
+ events: (id, query = {}) => this.request({
222
+ method: 'GET',
223
+ path: `/emails/${id}/events`,
224
+ query: query,
225
+ }),
226
+ /** The exact RFC 5322 source of this message, as text. */
227
+ mime: (id) => this.requestText({ method: 'GET', path: `/emails/${id}/mime` }),
228
+ /** The same message as a .eml file. */
229
+ eml: (id) => this.requestText({ method: 'GET', path: `/emails/${id}/eml` }),
230
+ /** One attachment's bytes, as they were sent. */
231
+ attachment: (id, attachmentId) => this.requestBytes({ method: 'GET', path: `/emails/${id}/attachments/${attachmentId}` }),
232
+ /** Cancel scheduled or queued messages by id, or everything scheduled before a time. */
233
+ bulkCancel: (payload, options) => this.request({
234
+ method: 'POST',
235
+ path: '/emails/bulk-cancel',
236
+ body: payload,
237
+ ...(options ? { options } : {}),
238
+ }),
239
+ /** The message log as CSV, with the same filters as list. */
240
+ export: (query = {}) => this.requestText({
241
+ method: 'GET',
242
+ path: '/emails/export.csv',
243
+ query: query,
244
+ }),
167
245
  /**
168
246
  * Move a scheduled email. The same act as `reschedule`, under the verb a
169
247
  * Resend integration already calls (M5.5).
@@ -190,6 +268,16 @@ export class AgentiSend {
190
268
  ...(options ? { options } : {}),
191
269
  }),
192
270
  delete: (id, options) => this.request({ method: 'DELETE', path: `/api-keys/${id}`, ...(options ? { options } : {}) }),
271
+ /**
272
+ * Issue a new token for this key. The old one keeps working for
273
+ * `grace_hours` (0, 1 or 24) so a deploy can pick up the new one.
274
+ */
275
+ rotate: (id, payload, options) => this.request({
276
+ method: 'POST',
277
+ path: `/api-keys/${id}/rotate`,
278
+ body: payload,
279
+ ...(options ? { options } : {}),
280
+ }),
193
281
  };
194
282
  domains = {
195
283
  create: (payload, options) => this.request({ method: 'POST', path: '/domains', body: payload, ...(options ? { options } : {}) }),
@@ -199,8 +287,10 @@ export class AgentiSend {
199
287
  query: query,
200
288
  }),
201
289
  get: (id) => this.request({ method: 'GET', path: `/domains/${id}` }),
290
+ /** One-shot DNS sheet: zone file, copy-paste commands, provider. */
291
+ setup: (id) => this.request({ method: 'GET', path: `/domains/${id}/setup` }),
202
292
  verify: (id, options) => this.request({ method: 'POST', path: `/domains/${id}/verify`, ...(options ? { options } : {}) }),
203
- /** A8 + P3b: click/open tracking, or a new tracking_subdomain. Never removed. */
293
+ /** A8 + P3b: click/open tracking, TLS mode, or a new tracking_subdomain. Never removed. */
204
294
  update: (id, payload, options) => this.request({
205
295
  method: 'PATCH',
206
296
  path: `/domains/${id}`,
@@ -208,6 +298,24 @@ export class AgentiSend {
208
298
  ...(options ? { options } : {}),
209
299
  }),
210
300
  delete: (id, options) => this.request({ method: 'DELETE', path: `/domains/${id}`, ...(options ? { options } : {}) }),
301
+ /**
302
+ * Long-poll until the domain is verified or failed, or `timeout` seconds
303
+ * (0-25) pass; 0 is a snapshot. It does not re-check DNS: the server checks
304
+ * on its own, and `next_poll_seconds` says when to ask again.
305
+ */
306
+ wait: (id, query = {}) => this.request({
307
+ method: 'GET',
308
+ path: `/domains/${id}/wait`,
309
+ query: query,
310
+ }),
311
+ /** Newest-first timeline: each DNS check, each record found or lost, verified, deleted. */
312
+ events: (id, query = {}) => this.request({
313
+ method: 'GET',
314
+ path: `/domains/${id}/events`,
315
+ query: query,
316
+ }),
317
+ /** Alias of setup: detects the DNS provider and returns the exact records to add. */
318
+ connect: (id) => this.request({ method: 'GET', path: `/domains/${id}/connect` }),
211
319
  };
212
320
  webhooks = {
213
321
  create: (payload, options) => this.request({ method: 'POST', path: '/webhooks', body: payload, ...(options ? { options } : {}) }),
@@ -238,6 +346,18 @@ export class AgentiSend {
238
346
  path: `/webhooks/${id}/dead-letters`,
239
347
  query: query,
240
348
  }),
349
+ /** Every delivery to this endpoint, with each attempt and what the receiver answered. */
350
+ deliveries: (id, query = {}) => this.request({
351
+ method: 'GET',
352
+ path: `/webhooks/${id}/deliveries`,
353
+ query: query,
354
+ }),
355
+ /** A new signing secret, returned once. The previous one keeps verifying for 24 hours. */
356
+ rotateSecret: (id, options) => this.request({
357
+ method: 'POST',
358
+ path: `/webhooks/${id}/rotate-secret`,
359
+ ...(options ? { options } : {}),
360
+ }),
241
361
  };
242
362
  limits = {
243
363
  list: (query = {}) => this.request({
@@ -264,6 +384,16 @@ export class AgentiSend {
264
384
  path: `/limits/keys/${apiKeyId}/resume`,
265
385
  ...(options ? { options } : {}),
266
386
  }),
387
+ /**
388
+ * Stop every key on the account sending, in one call. Undoing it is a
389
+ * person's decision, made in the console; no key can resume it.
390
+ */
391
+ killAll: (reason, options) => this.request({
392
+ method: 'POST',
393
+ path: '/limits/kill-all',
394
+ body: reason !== undefined ? { reason } : {},
395
+ ...(options ? { options } : {}),
396
+ }),
267
397
  };
268
398
  /** M5.5 — the rest of the verb surface a Resend integration calls. */
269
399
  /**
@@ -289,7 +419,31 @@ export class AgentiSend {
289
419
  query: query,
290
420
  }),
291
421
  get: (id) => this.request({ method: 'GET', path: `/emails/receiving/${id}` }),
422
+ /** Delete one received email for good. */
423
+ remove: (id, options) => this.request({
424
+ method: 'DELETE',
425
+ path: `/emails/receiving/${id}`,
426
+ ...(options ? { options } : {}),
427
+ }),
428
+ threads: (query = {}) => this.request({
429
+ method: 'GET',
430
+ path: '/emails/receiving/threads',
431
+ query: query,
432
+ }),
433
+ reply: (id, body, options) => this.request({
434
+ method: 'POST',
435
+ path: `/emails/receiving/${id}/reply`,
436
+ body,
437
+ ...(options ? { options } : {}),
438
+ }),
292
439
  attachments: (id) => this.request({ method: 'GET', path: `/emails/receiving/${id}/attachments` }),
440
+ /** One received attachment's bytes, served as an inert download. */
441
+ attachment: (id, attachmentId) => this.requestBytes({
442
+ method: 'GET',
443
+ path: `/emails/receiving/${id}/attachments/${attachmentId}`,
444
+ }),
445
+ /** The message exactly as it arrived, headers and all. */
446
+ raw: (id) => this.requestText({ method: 'GET', path: `/emails/receiving/${id}/raw` }),
293
447
  };
294
448
  /**
295
449
  * M5.7 — the custom-event registry. Declaring an event's fields turns a
@@ -356,6 +510,65 @@ export class AgentiSend {
356
510
  body: payload,
357
511
  ...(options ? { options } : {}),
358
512
  }),
513
+ /** Up to 1,000 contacts. Each item succeeds or fails on its own. */
514
+ 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. */
516
+ 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. */
518
+ segments: (id) => this.request({ method: 'GET', path: `/contacts/${id}/segments` }),
519
+ /** Refused: membership is the segment's rules. Names PATCH /segments/:id. */
520
+ addSegment: (id, segmentId, options) => this.request({
521
+ method: 'POST',
522
+ path: `/contacts/${id}/segments/${segmentId}`,
523
+ ...(options ? { options } : {}),
524
+ }),
525
+ /** Refused: membership is the segment's rules. Names PATCH /segments/:id. */
526
+ removeSegment: (id, segmentId, options) => this.request({
527
+ method: 'DELETE',
528
+ path: `/contacts/${id}/segments/${segmentId}`,
529
+ ...(options ? { options } : {}),
530
+ }),
531
+ /** Lift a marketing unsubscribe after the person opts back in. */
532
+ resubscribe: (id, payload, options) => this.request({
533
+ method: 'POST',
534
+ path: `/contacts/${id}/resubscribe`,
535
+ body: payload,
536
+ ...(options ? { options } : {}),
537
+ }),
538
+ };
539
+ /** Property names and types already stored on the account. */
540
+ contactProperties = {
541
+ list: () => this.request({ method: 'GET', path: '/contact-properties' }),
542
+ get: (id) => this.request({ method: 'GET', path: `/contact-properties/${id}` }),
543
+ };
544
+ /**
545
+ * The same contact list, at the paths the official SDK uses when a call
546
+ * names an audience. This account has one contact list.
547
+ */
548
+ audiences = {
549
+ createContact: (audienceId, payload, options) => this.request({
550
+ method: 'POST',
551
+ path: `/audiences/${audienceId}/contacts`,
552
+ body: payload,
553
+ ...(options ? { options } : {}),
554
+ }),
555
+ listContacts: (audienceId, query = {}) => this.request({
556
+ method: 'GET',
557
+ path: `/audiences/${audienceId}/contacts`,
558
+ query: query,
559
+ }),
560
+ getContact: (audienceId, id) => this.request({ method: 'GET', path: `/audiences/${audienceId}/contacts/${id}` }),
561
+ updateContact: (audienceId, id, payload, options) => this.request({
562
+ method: 'PATCH',
563
+ path: `/audiences/${audienceId}/contacts/${id}`,
564
+ body: payload,
565
+ ...(options ? { options } : {}),
566
+ }),
567
+ deleteContact: (audienceId, id, options) => this.request({
568
+ method: 'DELETE',
569
+ path: `/audiences/${audienceId}/contacts/${id}`,
570
+ ...(options ? { options } : {}),
571
+ }),
359
572
  };
360
573
  broadcasts = {
361
574
  create: (payload, options) => this.request({ method: 'POST', path: '/broadcasts', body: payload, ...(options ? { options } : {}) }),
@@ -365,8 +578,23 @@ export class AgentiSend {
365
578
  query: query,
366
579
  }),
367
580
  get: (id) => this.request({ method: 'GET', path: `/broadcasts/${id}` }),
581
+ /** Sent, delivered, opened, clicked, bounced, complained and unsubscribed. A test send is not included. */
582
+ stats: (id) => this.request({ method: 'GET', path: `/broadcasts/${id}/stats` }),
583
+ /** The rendered message. Nothing is sent. */
584
+ preview: (id) => this.request({ method: 'GET', path: `/broadcasts/${id}/preview` }),
368
585
  update: (id, payload, options) => this.request({ method: 'PATCH', path: `/broadcasts/${id}`, body: payload, ...(options ? { options } : {}) }),
369
- send: (id, options) => this.request({ method: 'POST', path: `/broadcasts/${id}/send`, ...(options ? { options } : {}) }),
586
+ /**
587
+ * Send now, or pass `scheduledAt` to schedule it instead (the same time
588
+ * grammar PATCH /broadcasts/:id accepts). Returns 200 when the broadcast
589
+ * has finished sending or was scheduled, and 202 while it is still
590
+ * sending. A 202 has status sending.
591
+ */
592
+ send: (id, payload, options) => this.request({
593
+ method: 'POST',
594
+ path: `/broadcasts/${id}/send`,
595
+ ...(payload?.scheduledAt !== undefined ? { body: { scheduled_at: payload.scheduledAt } } : {}),
596
+ ...(options ? { options } : {}),
597
+ }),
370
598
  /** Archive, not delete: a sent broadcast is history worth keeping (F14). */
371
599
  archive: (id, options) => this.request({ method: 'POST', path: `/broadcasts/${id}/archive`, ...(options ? { options } : {}) }),
372
600
  messages: (id, query = {}) => this.request({
@@ -374,7 +602,7 @@ export class AgentiSend {
374
602
  path: `/broadcasts/${id}/messages`,
375
603
  query: query,
376
604
  }),
377
- /** Cancel a scheduled broadcast: it returns to draft, editable again. */
605
+ /** 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. */
378
606
  cancel: (id, options) => this.request({
379
607
  method: 'POST',
380
608
  path: `/broadcasts/${id}/cancel`,
@@ -392,12 +620,40 @@ export class AgentiSend {
392
620
  update: (id, payload, options) => this.request({ method: 'PATCH', path: `/templates/${id}`, body: payload, ...(options ? { options } : {}) }),
393
621
  /** Snapshot the draft as an immutable version. Nothing already sent changes. */
394
622
  publish: (id, options) => this.request({ method: 'POST', path: `/templates/${id}/publish`, ...(options ? { options } : {}) }),
395
- render: (id, values = {}, versionNumber) => this.request({
623
+ /**
624
+ * `rendered` is the HTML; `text` is the plain-text part a markdown
625
+ * template yields. `preview: true` shows a missing required variable as
626
+ * `{{name}}` and lists it in `missing_variables` instead of failing.
627
+ */
628
+ render: (id, values = {}, versionNumber, options = {}) => this.request({
396
629
  method: 'POST',
397
630
  path: `/templates/${id}/render`,
398
- body: { values, ...(versionNumber !== undefined ? { version_number: versionNumber } : {}) },
631
+ body: {
632
+ values,
633
+ ...(versionNumber !== undefined ? { version_number: versionNumber } : {}),
634
+ ...(options.preview !== undefined ? { preview: options.preview } : {}),
635
+ },
399
636
  }),
637
+ /**
638
+ * Delete a template and its versions. Sent mail keeps its body and its
639
+ * template reference. Refused while a broadcast that has not been sent
640
+ * still uses it.
641
+ */
642
+ delete: (id, options) => this.request({ method: 'DELETE', path: `/templates/${id}`, ...(options ? { options } : {}) }),
400
643
  versions: (id) => this.request({ method: 'GET', path: `/templates/${id}/versions` }),
644
+ version: (id, versionNumber) => this.request({ method: 'GET', path: `/templates/${id}/versions/${versionNumber}` }),
645
+ /** Structured diff between two versions, or between a version and the draft. */
646
+ diff: (id, from, to) => this.request({ method: 'GET', path: `/templates/${id}/diff`, query: { from, to } }),
647
+ /**
648
+ * Start a new draft from an older version. History is never rewritten; the
649
+ * live version stays until that draft is published.
650
+ */
651
+ rollback: (id, toVersion, options) => this.request({
652
+ method: 'POST',
653
+ path: `/templates/${id}/rollback`,
654
+ body: { to_version: toVersion },
655
+ ...(options ? { options } : {}),
656
+ }),
401
657
  /** Copy a template into a fresh editable draft, history not included. */
402
658
  duplicate: (id, payload = {}, options) => this.request({
403
659
  method: 'POST',
@@ -413,6 +669,8 @@ export class AgentiSend {
413
669
  query: query,
414
670
  }),
415
671
  add: (payload, options) => this.request({ method: 'POST', path: '/suppressions', body: payload, ...(options ? { options } : {}) }),
672
+ /** The id or the address. */
673
+ get: (id, options) => this.request({ method: 'GET', path: `/suppressions/${id}`, ...(options ? { options } : {}) }),
416
674
  remove: (id, options) => this.request({ method: 'DELETE', path: `/suppressions/${id}`, ...(options ? { options } : {}) }),
417
675
  /** Up to 500 at a time. Each item succeeds or fails on its own. */
418
676
  batchAdd: (emails, level, options) => this.request({
@@ -442,6 +700,12 @@ export class AgentiSend {
442
700
  get: (id) => this.request({ method: 'GET', path: `/segments/${id}` }),
443
701
  update: (id, payload, options) => this.request({ method: 'PATCH', path: `/segments/${id}`, body: payload, ...(options ? { options } : {}) }),
444
702
  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
+ }),
445
709
  members: (id) => this.request({ method: 'GET', path: `/segments/${id}/members` }),
446
710
  };
447
711
  /**
@@ -526,9 +790,120 @@ export class AgentiSend {
526
790
  };
527
791
  /** Public per-component health — the same document the status page renders. */
528
792
  status = () => this.request({ method: 'GET', path: '/status' });
793
+ /** Daily uptime per component over the last 90 days, or `days`. A day nobody measured has no samples. */
794
+ statusHistory = (query = {}) => this.request({ method: 'GET', path: '/status/history', query });
795
+ /**
796
+ * Sending-domain DNS check. No API key. Ten checks a minute from one
797
+ * network. Returns the records to publish; stores nothing.
798
+ */
799
+ dnsCheck = (domain) => this.request({ method: 'GET', path: `/tools/dns/${encodeURIComponent(domain)}` });
800
+ /** Send, delivery and engagement figures with a daily series, over a window. */
801
+ metrics = (query = {}) => this.request({
802
+ method: 'GET',
803
+ path: '/metrics',
804
+ query: query,
805
+ });
806
+ /** This period's usage per key: budget, consumed, remaining, rate window, last used. */
807
+ usage = () => this.request({ method: 'GET', path: '/usage' });
808
+ account = {
809
+ /** Lifecycle status, the reason for it, and when the account was created. */
810
+ get: () => this.request({ method: 'GET', path: '/account' }),
811
+ /**
812
+ * Set the postal address printed in every broadcast footer. `null` clears
813
+ * it. A broadcast is not sent until the account has one.
814
+ */
815
+ update: (payload, options) => this.request({
816
+ method: 'PATCH',
817
+ path: '/account',
818
+ body: payload,
819
+ ...(options ? { options } : {}),
820
+ }),
821
+ };
529
822
  trust = {
530
823
  /** What the platform currently thinks of this account, in a shape an agent can branch on. */
531
824
  standing: () => this.request({ method: 'GET', path: '/trust/standing' }),
825
+ /** The published enforcement thresholds, as numbers. */
826
+ thresholds: () => this.request({ method: 'GET', path: '/trust/thresholds' }),
827
+ /** Appeal the current standing. The reason is recorded verbatim; a person answers by `sla_deadline_at`. */
828
+ appeal: (reason, options) => this.request({
829
+ method: 'POST',
830
+ path: '/trust/appeal',
831
+ body: { reason },
832
+ ...(options ? { options } : {}),
833
+ }),
834
+ /** The remediation checklist, with what has been ticked. */
835
+ remediation: () => this.request({ method: 'GET', path: '/trust/remediation' }),
836
+ /** Tick or untick one checklist item. Returns the whole checklist. */
837
+ setRemediation: (payload, options) => this.request({
838
+ method: 'POST',
839
+ path: '/trust/remediation',
840
+ body: payload,
841
+ ...(options ? { options } : {}),
842
+ }),
843
+ };
844
+ /**
845
+ * Sends held for a person to approve, and what they decided. Approving or
846
+ * rejecting is done in the console; a key can list, never decide.
847
+ */
848
+ agentActions = {
849
+ list: (query = {}) => this.request({
850
+ method: 'GET',
851
+ path: '/agent-actions',
852
+ query: query,
853
+ }),
854
+ };
855
+ /** Conditions this account should know about: a spent budget, a kill switch, a lost domain. */
856
+ notifications = {
857
+ list: (query = {}) => this.request({
858
+ method: 'GET',
859
+ path: '/notifications',
860
+ query: query,
861
+ }),
862
+ read: (id, options) => this.request({
863
+ method: 'POST',
864
+ path: `/notifications/${id}/read`,
865
+ ...(options ? { options } : {}),
866
+ }),
867
+ readAll: (options) => this.request({ method: 'POST', path: '/notifications/read', ...(options ? { options } : {}) }),
868
+ preferences: () => this.request({ method: 'GET', path: '/notifications/preferences' }),
869
+ setPreferences: (preferences, options) => this.request({
870
+ method: 'PATCH',
871
+ path: '/notifications/preferences',
872
+ body: { preferences },
873
+ ...(options ? { options } : {}),
874
+ }),
875
+ };
876
+ dedicatedIps = {
877
+ list: (query = {}) => this.request({
878
+ method: 'GET',
879
+ path: '/dedicated-ips',
880
+ query: query,
881
+ }),
882
+ /** Provision a dedicated IP. It starts warming on the published curve. */
883
+ provision: (payload, options) => this.request({
884
+ method: 'POST',
885
+ path: '/dedicated-ips',
886
+ body: payload,
887
+ ...(options ? { options } : {}),
888
+ }),
889
+ release: (id, options) => this.request({ method: 'DELETE', path: `/dedicated-ips/${id}`, ...(options ? { options } : {}) }),
890
+ /** The published warmup curve: how volume moves, and when. */
891
+ ramp: () => this.request({ method: 'GET', path: '/dedicated-ips/ramp' }),
892
+ /** Which route this message would take right now, by the same math the send path uses. */
893
+ routeDecision: (messageId) => this.request({ method: 'GET', path: `/dedicated-ips/route-decision/${messageId}` }),
894
+ };
895
+ deliverability = {
896
+ /** Every sending domain with its standing over the window, worst first. */
897
+ domains: (query = {}) => this.request({ method: 'GET', path: '/deliverability/domains', query }),
898
+ domain: (id) => this.request({ method: 'GET', path: `/deliverability/domains/${id}` }),
899
+ /** Persist today's rates as a snapshot. Idempotent per domain per day. */
900
+ snapshot: (id, options) => this.request({
901
+ method: 'POST',
902
+ path: `/deliverability/domains/${id}/snapshot`,
903
+ ...(options ? { options } : {}),
904
+ }),
905
+ /** Aggregate authentication reports: aligned and failing volume per day, and every address sending as you. */
906
+ dmarc: (query = {}) => this.request({ method: 'GET', path: '/deliverability/dmarc', query }),
532
907
  };
533
908
  billing = {
534
909
  /**
@@ -537,6 +912,8 @@ export class AgentiSend {
537
912
  * budget comes from Starter; only a signed-in human in the console can buy.
538
913
  */
539
914
  plan: () => this.request({ method: 'GET', path: '/billing/plan' }),
915
+ /** Plan, usage against each published limit, and what the next tier changes. Buying stays in the console. */
916
+ get: () => this.request({ method: 'GET', path: '/billing' }),
540
917
  };
541
918
  }
542
919
  //# sourceMappingURL=client.js.map