@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/README.md +12 -8
- package/dist/cli/commands.js +2 -1
- package/dist/cli/commands.js.map +1 -1
- package/dist/cli/main.js +5 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/scheduled-at.d.ts +4 -3
- package/dist/cli/scheduled-at.js +86 -12
- package/dist/cli/scheduled-at.js.map +1 -1
- package/dist/client.d.ts +346 -6
- package/dist/client.js +398 -21
- package/dist/client.js.map +1 -1
- package/dist/compat-resend.d.ts +311 -50
- package/dist/compat-resend.js +500 -78
- package/dist/compat-resend.js.map +1 -1
- package/dist/errors.d.ts +7 -0
- package/dist/errors.js +38 -0
- package/dist/errors.js.map +1 -1
- package/dist/types.d.ts +102 -7
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/webhook-signing.d.ts +37 -1
- package/dist/webhook-signing.js +85 -16
- package/dist/webhook-signing.js.map +1 -1
- package/package.json +15 -10
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
|
-
|
|
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
|
-
|
|
85
|
+
send(raw, accept) {
|
|
84
86
|
const headers = {
|
|
85
87
|
authorization: `Bearer ${this.apiKey}`,
|
|
86
|
-
accept
|
|
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
|
-
|
|
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
|
-
|
|
117
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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: {
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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: {
|
|
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
|