@agentisend/sdk-node 0.2.0 → 0.5.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 +332 -6
- package/dist/client.js +388 -21
- package/dist/client.js.map +1 -1
- package/dist/compat-resend.d.ts +311 -50
- package/dist/compat-resend.js +499 -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 +79 -7
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/dist/webhook-signing.d.ts +28 -1
- package/dist/webhook-signing.js +76 -16
- package/dist/webhook-signing.js.map +1 -1
- package/package.json +8 -2
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 } : {}) }),
|
|
@@ -155,11 +191,20 @@ export class AgentiSend {
|
|
|
155
191
|
path: `/emails/${id}/cancel`,
|
|
156
192
|
...(options ? { options } : {}),
|
|
157
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
|
+
}),
|
|
158
200
|
/** Move an email to a new time. Works from scheduled AND canceled. */
|
|
159
201
|
reschedule: (id, scheduledAt, options) => this.request({
|
|
160
202
|
method: 'POST',
|
|
161
203
|
path: `/emails/${id}/reschedule`,
|
|
162
|
-
body: {
|
|
204
|
+
body: {
|
|
205
|
+
scheduled_at: scheduledAt,
|
|
206
|
+
...(options?.timezone !== undefined ? { timezone: options.timezone } : {}),
|
|
207
|
+
},
|
|
163
208
|
...(options ? { options } : {}),
|
|
164
209
|
}),
|
|
165
210
|
/**
|
|
@@ -170,6 +215,33 @@ export class AgentiSend {
|
|
|
170
215
|
explain: (id) => this.request({ method: 'GET', path: `/emails/${id}/explain` }),
|
|
171
216
|
/** Run every gate without sending or spending. Free, always. */
|
|
172
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
|
+
}),
|
|
173
245
|
/**
|
|
174
246
|
* Move a scheduled email. The same act as `reschedule`, under the verb a
|
|
175
247
|
* Resend integration already calls (M5.5).
|
|
@@ -196,6 +268,16 @@ export class AgentiSend {
|
|
|
196
268
|
...(options ? { options } : {}),
|
|
197
269
|
}),
|
|
198
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
|
+
}),
|
|
199
281
|
};
|
|
200
282
|
domains = {
|
|
201
283
|
create: (payload, options) => this.request({ method: 'POST', path: '/domains', body: payload, ...(options ? { options } : {}) }),
|
|
@@ -205,8 +287,10 @@ export class AgentiSend {
|
|
|
205
287
|
query: query,
|
|
206
288
|
}),
|
|
207
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` }),
|
|
208
292
|
verify: (id, options) => this.request({ method: 'POST', path: `/domains/${id}/verify`, ...(options ? { options } : {}) }),
|
|
209
|
-
/** 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. */
|
|
210
294
|
update: (id, payload, options) => this.request({
|
|
211
295
|
method: 'PATCH',
|
|
212
296
|
path: `/domains/${id}`,
|
|
@@ -214,6 +298,24 @@ export class AgentiSend {
|
|
|
214
298
|
...(options ? { options } : {}),
|
|
215
299
|
}),
|
|
216
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` }),
|
|
217
319
|
};
|
|
218
320
|
webhooks = {
|
|
219
321
|
create: (payload, options) => this.request({ method: 'POST', path: '/webhooks', body: payload, ...(options ? { options } : {}) }),
|
|
@@ -244,6 +346,18 @@ export class AgentiSend {
|
|
|
244
346
|
path: `/webhooks/${id}/dead-letters`,
|
|
245
347
|
query: query,
|
|
246
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
|
+
}),
|
|
247
361
|
};
|
|
248
362
|
limits = {
|
|
249
363
|
list: (query = {}) => this.request({
|
|
@@ -270,6 +384,16 @@ export class AgentiSend {
|
|
|
270
384
|
path: `/limits/keys/${apiKeyId}/resume`,
|
|
271
385
|
...(options ? { options } : {}),
|
|
272
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
|
+
}),
|
|
273
397
|
};
|
|
274
398
|
/** M5.5 — the rest of the verb surface a Resend integration calls. */
|
|
275
399
|
/**
|
|
@@ -295,6 +419,12 @@ export class AgentiSend {
|
|
|
295
419
|
query: query,
|
|
296
420
|
}),
|
|
297
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
|
+
}),
|
|
298
428
|
threads: (query = {}) => this.request({
|
|
299
429
|
method: 'GET',
|
|
300
430
|
path: '/emails/receiving/threads',
|
|
@@ -307,6 +437,13 @@ export class AgentiSend {
|
|
|
307
437
|
...(options ? { options } : {}),
|
|
308
438
|
}),
|
|
309
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` }),
|
|
310
447
|
};
|
|
311
448
|
/**
|
|
312
449
|
* M5.7 — the custom-event registry. Declaring an event's fields turns a
|
|
@@ -373,6 +510,65 @@ export class AgentiSend {
|
|
|
373
510
|
body: payload,
|
|
374
511
|
...(options ? { options } : {}),
|
|
375
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
|
+
}),
|
|
376
572
|
};
|
|
377
573
|
broadcasts = {
|
|
378
574
|
create: (payload, options) => this.request({ method: 'POST', path: '/broadcasts', body: payload, ...(options ? { options } : {}) }),
|
|
@@ -382,8 +578,23 @@ export class AgentiSend {
|
|
|
382
578
|
query: query,
|
|
383
579
|
}),
|
|
384
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` }),
|
|
385
585
|
update: (id, payload, options) => this.request({ method: 'PATCH', path: `/broadcasts/${id}`, body: payload, ...(options ? { options } : {}) }),
|
|
386
|
-
|
|
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
|
+
}),
|
|
387
598
|
/** Archive, not delete: a sent broadcast is history worth keeping (F14). */
|
|
388
599
|
archive: (id, options) => this.request({ method: 'POST', path: `/broadcasts/${id}/archive`, ...(options ? { options } : {}) }),
|
|
389
600
|
messages: (id, query = {}) => this.request({
|
|
@@ -391,12 +602,19 @@ export class AgentiSend {
|
|
|
391
602
|
path: `/broadcasts/${id}/messages`,
|
|
392
603
|
query: query,
|
|
393
604
|
}),
|
|
394
|
-
/** 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. */
|
|
395
606
|
cancel: (id, options) => this.request({
|
|
396
607
|
method: 'POST',
|
|
397
608
|
path: `/broadcasts/${id}/cancel`,
|
|
398
609
|
...(options ? { options } : {}),
|
|
399
610
|
}),
|
|
611
|
+
/** Copy a broadcast into a new draft: the message, segment, reply_to, preview_text and topic_id. No schedule, sends or history. */
|
|
612
|
+
duplicate: (id, payload = {}, options) => this.request({
|
|
613
|
+
method: 'POST',
|
|
614
|
+
path: `/broadcasts/${id}/duplicate`,
|
|
615
|
+
body: payload,
|
|
616
|
+
...(options ? { options } : {}),
|
|
617
|
+
}),
|
|
400
618
|
};
|
|
401
619
|
templates = {
|
|
402
620
|
create: (payload, options) => this.request({ method: 'POST', path: '/templates', body: payload, ...(options ? { options } : {}) }),
|
|
@@ -409,12 +627,40 @@ export class AgentiSend {
|
|
|
409
627
|
update: (id, payload, options) => this.request({ method: 'PATCH', path: `/templates/${id}`, body: payload, ...(options ? { options } : {}) }),
|
|
410
628
|
/** Snapshot the draft as an immutable version. Nothing already sent changes. */
|
|
411
629
|
publish: (id, options) => this.request({ method: 'POST', path: `/templates/${id}/publish`, ...(options ? { options } : {}) }),
|
|
412
|
-
|
|
630
|
+
/**
|
|
631
|
+
* `rendered` is the HTML; `text` is the plain-text part a markdown
|
|
632
|
+
* template yields. `preview: true` shows a missing required variable as
|
|
633
|
+
* `{{name}}` and lists it in `missing_variables` instead of failing.
|
|
634
|
+
*/
|
|
635
|
+
render: (id, values = {}, versionNumber, options = {}) => this.request({
|
|
413
636
|
method: 'POST',
|
|
414
637
|
path: `/templates/${id}/render`,
|
|
415
|
-
body: {
|
|
638
|
+
body: {
|
|
639
|
+
values,
|
|
640
|
+
...(versionNumber !== undefined ? { version_number: versionNumber } : {}),
|
|
641
|
+
...(options.preview !== undefined ? { preview: options.preview } : {}),
|
|
642
|
+
},
|
|
416
643
|
}),
|
|
644
|
+
/**
|
|
645
|
+
* Delete a template and its versions. Sent mail keeps its body and its
|
|
646
|
+
* template reference. Refused while a broadcast that has not been sent
|
|
647
|
+
* still uses it.
|
|
648
|
+
*/
|
|
649
|
+
delete: (id, options) => this.request({ method: 'DELETE', path: `/templates/${id}`, ...(options ? { options } : {}) }),
|
|
417
650
|
versions: (id) => this.request({ method: 'GET', path: `/templates/${id}/versions` }),
|
|
651
|
+
version: (id, versionNumber) => this.request({ method: 'GET', path: `/templates/${id}/versions/${versionNumber}` }),
|
|
652
|
+
/** Structured diff between two versions, or between a version and the draft. */
|
|
653
|
+
diff: (id, from, to) => this.request({ method: 'GET', path: `/templates/${id}/diff`, query: { from, to } }),
|
|
654
|
+
/**
|
|
655
|
+
* Start a new draft from an older version. History is never rewritten; the
|
|
656
|
+
* live version stays until that draft is published.
|
|
657
|
+
*/
|
|
658
|
+
rollback: (id, toVersion, options) => this.request({
|
|
659
|
+
method: 'POST',
|
|
660
|
+
path: `/templates/${id}/rollback`,
|
|
661
|
+
body: { to_version: toVersion },
|
|
662
|
+
...(options ? { options } : {}),
|
|
663
|
+
}),
|
|
418
664
|
/** Copy a template into a fresh editable draft, history not included. */
|
|
419
665
|
duplicate: (id, payload = {}, options) => this.request({
|
|
420
666
|
method: 'POST',
|
|
@@ -430,6 +676,8 @@ export class AgentiSend {
|
|
|
430
676
|
query: query,
|
|
431
677
|
}),
|
|
432
678
|
add: (payload, options) => this.request({ method: 'POST', path: '/suppressions', body: payload, ...(options ? { options } : {}) }),
|
|
679
|
+
/** The id or the address. */
|
|
680
|
+
get: (id, options) => this.request({ method: 'GET', path: `/suppressions/${id}`, ...(options ? { options } : {}) }),
|
|
433
681
|
remove: (id, options) => this.request({ method: 'DELETE', path: `/suppressions/${id}`, ...(options ? { options } : {}) }),
|
|
434
682
|
/** Up to 500 at a time. Each item succeeds or fails on its own. */
|
|
435
683
|
batchAdd: (emails, level, options) => this.request({
|
|
@@ -459,6 +707,12 @@ export class AgentiSend {
|
|
|
459
707
|
get: (id) => this.request({ method: 'GET', path: `/segments/${id}` }),
|
|
460
708
|
update: (id, payload, options) => this.request({ method: 'PATCH', path: `/segments/${id}`, body: payload, ...(options ? { options } : {}) }),
|
|
461
709
|
delete: (id, options) => this.request({ method: 'DELETE', path: `/segments/${id}`, ...(options ? { options } : {}) }),
|
|
710
|
+
/** The account contact list. An audience id on this path does not select a second list. */
|
|
711
|
+
contacts: (id, query = {}) => this.request({
|
|
712
|
+
method: 'GET',
|
|
713
|
+
path: `/segments/${id}/contacts`,
|
|
714
|
+
query: query,
|
|
715
|
+
}),
|
|
462
716
|
members: (id) => this.request({ method: 'GET', path: `/segments/${id}/members` }),
|
|
463
717
|
};
|
|
464
718
|
/**
|
|
@@ -543,9 +797,120 @@ export class AgentiSend {
|
|
|
543
797
|
};
|
|
544
798
|
/** Public per-component health — the same document the status page renders. */
|
|
545
799
|
status = () => this.request({ method: 'GET', path: '/status' });
|
|
800
|
+
/** Daily uptime per component over the last 90 days, or `days`. A day nobody measured has no samples. */
|
|
801
|
+
statusHistory = (query = {}) => this.request({ method: 'GET', path: '/status/history', query });
|
|
802
|
+
/**
|
|
803
|
+
* Sending-domain DNS check. No API key. Ten checks a minute from one
|
|
804
|
+
* network. Returns the records to publish; stores nothing.
|
|
805
|
+
*/
|
|
806
|
+
dnsCheck = (domain) => this.request({ method: 'GET', path: `/tools/dns/${encodeURIComponent(domain)}` });
|
|
807
|
+
/** Send, delivery and engagement figures with a daily series, over a window. */
|
|
808
|
+
metrics = (query = {}) => this.request({
|
|
809
|
+
method: 'GET',
|
|
810
|
+
path: '/metrics',
|
|
811
|
+
query: query,
|
|
812
|
+
});
|
|
813
|
+
/** This period's usage per key: budget, consumed, remaining, rate window, last used. */
|
|
814
|
+
usage = () => this.request({ method: 'GET', path: '/usage' });
|
|
815
|
+
account = {
|
|
816
|
+
/** Lifecycle status, the reason for it, and when the account was created. */
|
|
817
|
+
get: () => this.request({ method: 'GET', path: '/account' }),
|
|
818
|
+
/**
|
|
819
|
+
* Set the postal address printed in every broadcast footer. `null` clears
|
|
820
|
+
* it. A broadcast is not sent until the account has one.
|
|
821
|
+
*/
|
|
822
|
+
update: (payload, options) => this.request({
|
|
823
|
+
method: 'PATCH',
|
|
824
|
+
path: '/account',
|
|
825
|
+
body: payload,
|
|
826
|
+
...(options ? { options } : {}),
|
|
827
|
+
}),
|
|
828
|
+
};
|
|
546
829
|
trust = {
|
|
547
830
|
/** What the platform currently thinks of this account, in a shape an agent can branch on. */
|
|
548
831
|
standing: () => this.request({ method: 'GET', path: '/trust/standing' }),
|
|
832
|
+
/** The published enforcement thresholds, as numbers. */
|
|
833
|
+
thresholds: () => this.request({ method: 'GET', path: '/trust/thresholds' }),
|
|
834
|
+
/** Appeal the current standing. The reason is recorded verbatim; a person answers by `sla_deadline_at`. */
|
|
835
|
+
appeal: (reason, options) => this.request({
|
|
836
|
+
method: 'POST',
|
|
837
|
+
path: '/trust/appeal',
|
|
838
|
+
body: { reason },
|
|
839
|
+
...(options ? { options } : {}),
|
|
840
|
+
}),
|
|
841
|
+
/** The remediation checklist, with what has been ticked. */
|
|
842
|
+
remediation: () => this.request({ method: 'GET', path: '/trust/remediation' }),
|
|
843
|
+
/** Tick or untick one checklist item. Returns the whole checklist. */
|
|
844
|
+
setRemediation: (payload, options) => this.request({
|
|
845
|
+
method: 'POST',
|
|
846
|
+
path: '/trust/remediation',
|
|
847
|
+
body: payload,
|
|
848
|
+
...(options ? { options } : {}),
|
|
849
|
+
}),
|
|
850
|
+
};
|
|
851
|
+
/**
|
|
852
|
+
* Sends held for a person to approve, and what they decided. Approving or
|
|
853
|
+
* rejecting is done in the console; a key can list, never decide.
|
|
854
|
+
*/
|
|
855
|
+
agentActions = {
|
|
856
|
+
list: (query = {}) => this.request({
|
|
857
|
+
method: 'GET',
|
|
858
|
+
path: '/agent-actions',
|
|
859
|
+
query: query,
|
|
860
|
+
}),
|
|
861
|
+
};
|
|
862
|
+
/** Conditions this account should know about: a spent budget, a kill switch, a lost domain. */
|
|
863
|
+
notifications = {
|
|
864
|
+
list: (query = {}) => this.request({
|
|
865
|
+
method: 'GET',
|
|
866
|
+
path: '/notifications',
|
|
867
|
+
query: query,
|
|
868
|
+
}),
|
|
869
|
+
read: (id, options) => this.request({
|
|
870
|
+
method: 'POST',
|
|
871
|
+
path: `/notifications/${id}/read`,
|
|
872
|
+
...(options ? { options } : {}),
|
|
873
|
+
}),
|
|
874
|
+
readAll: (options) => this.request({ method: 'POST', path: '/notifications/read', ...(options ? { options } : {}) }),
|
|
875
|
+
preferences: () => this.request({ method: 'GET', path: '/notifications/preferences' }),
|
|
876
|
+
setPreferences: (preferences, options) => this.request({
|
|
877
|
+
method: 'PATCH',
|
|
878
|
+
path: '/notifications/preferences',
|
|
879
|
+
body: { preferences },
|
|
880
|
+
...(options ? { options } : {}),
|
|
881
|
+
}),
|
|
882
|
+
};
|
|
883
|
+
dedicatedIps = {
|
|
884
|
+
list: (query = {}) => this.request({
|
|
885
|
+
method: 'GET',
|
|
886
|
+
path: '/dedicated-ips',
|
|
887
|
+
query: query,
|
|
888
|
+
}),
|
|
889
|
+
/** Provision a dedicated IP. It starts warming on the published curve. */
|
|
890
|
+
provision: (payload, options) => this.request({
|
|
891
|
+
method: 'POST',
|
|
892
|
+
path: '/dedicated-ips',
|
|
893
|
+
body: payload,
|
|
894
|
+
...(options ? { options } : {}),
|
|
895
|
+
}),
|
|
896
|
+
release: (id, options) => this.request({ method: 'DELETE', path: `/dedicated-ips/${id}`, ...(options ? { options } : {}) }),
|
|
897
|
+
/** The published warmup curve: how volume moves, and when. */
|
|
898
|
+
ramp: () => this.request({ method: 'GET', path: '/dedicated-ips/ramp' }),
|
|
899
|
+
/** Which route this message would take right now, by the same math the send path uses. */
|
|
900
|
+
routeDecision: (messageId) => this.request({ method: 'GET', path: `/dedicated-ips/route-decision/${messageId}` }),
|
|
901
|
+
};
|
|
902
|
+
deliverability = {
|
|
903
|
+
/** Every sending domain with its standing over the window, worst first. */
|
|
904
|
+
domains: (query = {}) => this.request({ method: 'GET', path: '/deliverability/domains', query }),
|
|
905
|
+
domain: (id) => this.request({ method: 'GET', path: `/deliverability/domains/${id}` }),
|
|
906
|
+
/** Persist today's rates as a snapshot. Idempotent per domain per day. */
|
|
907
|
+
snapshot: (id, options) => this.request({
|
|
908
|
+
method: 'POST',
|
|
909
|
+
path: `/deliverability/domains/${id}/snapshot`,
|
|
910
|
+
...(options ? { options } : {}),
|
|
911
|
+
}),
|
|
912
|
+
/** Aggregate authentication reports: aligned and failing volume per day, and every address sending as you. */
|
|
913
|
+
dmarc: (query = {}) => this.request({ method: 'GET', path: '/deliverability/dmarc', query }),
|
|
549
914
|
};
|
|
550
915
|
billing = {
|
|
551
916
|
/**
|
|
@@ -554,6 +919,8 @@ export class AgentiSend {
|
|
|
554
919
|
* budget comes from Starter; only a signed-in human in the console can buy.
|
|
555
920
|
*/
|
|
556
921
|
plan: () => this.request({ method: 'GET', path: '/billing/plan' }),
|
|
922
|
+
/** Plan, usage against each published limit, and what the next tier changes. Buying stays in the console. */
|
|
923
|
+
get: () => this.request({ method: 'GET', path: '/billing' }),
|
|
557
924
|
};
|
|
558
925
|
}
|
|
559
926
|
//# sourceMappingURL=client.js.map
|