@marlinjai/mail-sdk 0.2.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.
@@ -0,0 +1,4480 @@
1
+ import * as _marlinjai_mail_contract from '@marlinjai/mail-contract';
2
+ import { UsageWarningHeaderEntry, CompileMessage, OperationId, RouteParams, RouteQuery, RouteBody, RouteResponse, Page, ErrorCode } from '@marlinjai/mail-contract';
3
+ export * from '@marlinjai/mail-contract';
4
+ import * as zod from 'zod';
5
+
6
+ /** Produces the auth headers for one request. A dashboard client varies these per call. */
7
+ type AuthHeaderProvider = () => Record<string, string>;
8
+ interface CoreConfig {
9
+ baseUrl: string;
10
+ authHeaders: AuthHeaderProvider;
11
+ fetch: typeof fetch;
12
+ timeoutMs: number;
13
+ maxRetries: number;
14
+ userAgent?: string;
15
+ validateResponses: boolean;
16
+ /** Test hooks only; production callers never set these. */
17
+ sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
18
+ random?: () => number;
19
+ }
20
+ /** What a successful response carried besides its body. */
21
+ interface ResponseMeta {
22
+ status: number;
23
+ /** The service's request id, quoted in support requests. */
24
+ requestId: string | null;
25
+ /** Every response header, for anything this type does not lift out. */
26
+ headers: Headers;
27
+ /**
28
+ * The USAGE_WARNING_HEADER, parsed: each plan limit the workspace is at or
29
+ * above USAGE_WARNING_RATIO of. Empty when the header was absent (the service
30
+ * sends it on `mailings.send` and `mailings.test`).
31
+ */
32
+ usageWarnings: UsageWarningHeaderEntry[];
33
+ }
34
+ interface RequestOpts {
35
+ /** Reused across every retry of this call. Auto-generated when omitted. */
36
+ idempotencyKey?: string;
37
+ signal?: AbortSignal;
38
+ /**
39
+ * Called with the successful response's metadata once its body parsed and
40
+ * validated, just before it is returned: once per call, once per page for
41
+ * `paginate`. Not called when the call fails: a `MailApiError` carries its own
42
+ * status and request id. An exception thrown here propagates to the caller.
43
+ */
44
+ onResponse?: (meta: ResponseMeta) => void;
45
+ }
46
+ interface ExecuteArgs<K extends OperationId> {
47
+ params?: RouteParams<K>;
48
+ query?: RouteQuery<K>;
49
+ body?: RouteBody<K>;
50
+ }
51
+ /** A file the service answered with (`templates.export`, `mailings.export`). */
52
+ interface ExportedFile {
53
+ /** The file's text: MJML or HTML. */
54
+ content: string;
55
+ /** e.g. `text/html; charset=utf-8`. */
56
+ contentType: string;
57
+ /** From `Content-Disposition`, e.g. `Herbst-Newsletter.html`. */
58
+ filename: string;
59
+ /**
60
+ * What would block sending this content (MJML errors, addresses the
61
+ * workspace's asset policy does not allow). An export is never refused for
62
+ * them; they come in EXPORT_WARNINGS_HEADER, shortened to fit.
63
+ */
64
+ warnings: CompileMessage[];
65
+ /** How many warnings there are in all; more than `warnings.length` when the header was shortened. */
66
+ warningCount: number;
67
+ requestId: string | null;
68
+ }
69
+ /** The `filename` of a `Content-Disposition` value (the `filename*` UTF-8 form first). */
70
+ declare function dispositionFilename(value: string | null): string | null;
71
+
72
+ /**
73
+ * Namespaced, hand-written wrappers over `execute`/`executeMultipart`. Every
74
+ * method names its operation id as a literal, so its parameter and return types
75
+ * are inferred straight from `@marlinjai/mail-contract`'s `RouteBody`/`RouteQuery`/
76
+ * `RouteResponse`: nothing here redefines a shape the contract already owns.
77
+ *
78
+ * `opts` (an `Idempotency-Key` override, an `AbortSignal`) is the last, optional
79
+ * argument of every mutating method.
80
+ */
81
+ declare function createNamespaces(config: CoreConfig): {
82
+ /**
83
+ * `workspaces` (plural) is the dashboard-only pair for a person with no
84
+ * workspace context yet: creating one, and listing the ones they belong to.
85
+ * `workspace` (singular, below) is the ordinary per-workspace read/update,
86
+ * reachable with a workspace API key or a dashboard call already bound to one.
87
+ */
88
+ workspaces: {
89
+ create: (body: RouteBody<"workspaces.create">, opts?: RequestOpts) => Promise<{
90
+ id: string;
91
+ name: string;
92
+ created_at: string;
93
+ updated_at: string;
94
+ slug: string;
95
+ settings: {
96
+ asset_policy: "any" | "service_only";
97
+ default_locale: string;
98
+ locales: string[];
99
+ tracking_enabled: boolean;
100
+ default_timezone: string | null;
101
+ };
102
+ company_id: string | null;
103
+ }>;
104
+ list: (query?: RouteQuery<"workspaces.list">, opts?: RequestOpts) => Promise<{
105
+ data: {
106
+ id: string;
107
+ name: string;
108
+ created_at: string;
109
+ updated_at: string;
110
+ slug: string;
111
+ settings: {
112
+ asset_policy: "any" | "service_only";
113
+ default_locale: string;
114
+ locales: string[];
115
+ tracking_enabled: boolean;
116
+ default_timezone: string | null;
117
+ };
118
+ company_id: string | null;
119
+ role: "owner" | "admin" | "editor" | "viewer";
120
+ }[];
121
+ next_cursor: string | null;
122
+ }>;
123
+ };
124
+ workspace: {
125
+ get: (opts?: RequestOpts) => Promise<{
126
+ id: string;
127
+ name: string;
128
+ created_at: string;
129
+ updated_at: string;
130
+ slug: string;
131
+ settings: {
132
+ asset_policy: "any" | "service_only";
133
+ default_locale: string;
134
+ locales: string[];
135
+ tracking_enabled: boolean;
136
+ default_timezone: string | null;
137
+ };
138
+ company_id: string | null;
139
+ }>;
140
+ update: (body: RouteBody<"workspace.update">, opts?: RequestOpts) => Promise<{
141
+ id: string;
142
+ name: string;
143
+ created_at: string;
144
+ updated_at: string;
145
+ slug: string;
146
+ settings: {
147
+ asset_policy: "any" | "service_only";
148
+ default_locale: string;
149
+ locales: string[];
150
+ tracking_enabled: boolean;
151
+ default_timezone: string | null;
152
+ };
153
+ company_id: string | null;
154
+ }>;
155
+ /**
156
+ * Hands the workspace to another auth-brain company (owner only, and a
157
+ * workspace API key is refused outright). What changes is whose erasure
158
+ * takes the workspace with it, nothing about billing or who may sign in.
159
+ */
160
+ move: (body: RouteBody<"workspace.move">, opts?: RequestOpts) => Promise<{
161
+ id: string;
162
+ name: string;
163
+ created_at: string;
164
+ updated_at: string;
165
+ slug: string;
166
+ settings: {
167
+ asset_policy: "any" | "service_only";
168
+ default_locale: string;
169
+ locales: string[];
170
+ tracking_enabled: boolean;
171
+ default_timezone: string | null;
172
+ };
173
+ company_id: string | null;
174
+ }>;
175
+ };
176
+ members: {
177
+ list: (query?: RouteQuery<"members.list">, opts?: RequestOpts) => Promise<{
178
+ data: {
179
+ id: string;
180
+ name: string | null;
181
+ created_at: string;
182
+ subject: string;
183
+ email: string;
184
+ role: "owner" | "admin" | "editor" | "viewer";
185
+ }[];
186
+ next_cursor: string | null;
187
+ }>;
188
+ /**
189
+ * The service binds people by auth-brain subject only (it never sees a
190
+ * login), so the caller resolves the person first and sends the subject
191
+ * with their email and name.
192
+ */
193
+ add: (body: RouteBody<"members.add">, opts?: RequestOpts) => Promise<{
194
+ id: string;
195
+ name: string | null;
196
+ created_at: string;
197
+ subject: string;
198
+ email: string;
199
+ role: "owner" | "admin" | "editor" | "viewer";
200
+ }>;
201
+ update: (id: string, body: RouteBody<"members.update">, opts?: RequestOpts) => Promise<{
202
+ id: string;
203
+ name: string | null;
204
+ created_at: string;
205
+ subject: string;
206
+ email: string;
207
+ role: "owner" | "admin" | "editor" | "viewer";
208
+ }>;
209
+ remove: (id: string, opts?: RequestOpts) => Promise<{
210
+ ok: true;
211
+ }>;
212
+ };
213
+ /**
214
+ * Invitations: an admin invites an address with a role (the token is in
215
+ * the create response only); the invited person accepts through the
216
+ * dashboard (`accept` is dashboard-only and names the signed-in person).
217
+ */
218
+ invites: {
219
+ create: (body: RouteBody<"invites.create">, opts?: RequestOpts) => Promise<{
220
+ invite: {
221
+ status: "pending" | "accepted" | "revoked" | "expired";
222
+ id: string;
223
+ created_at: string;
224
+ email: string;
225
+ role: "owner" | "admin" | "editor" | "viewer";
226
+ revoked_at: string | null;
227
+ invited_by: {
228
+ email: string | null;
229
+ member_id: string | null;
230
+ };
231
+ expires_at: string;
232
+ accepted_at: string | null;
233
+ };
234
+ token: string;
235
+ }>;
236
+ list: (query?: RouteQuery<"invites.list">, opts?: RequestOpts) => Promise<{
237
+ data: {
238
+ status: "pending" | "accepted" | "revoked" | "expired";
239
+ id: string;
240
+ created_at: string;
241
+ email: string;
242
+ role: "owner" | "admin" | "editor" | "viewer";
243
+ revoked_at: string | null;
244
+ invited_by: {
245
+ email: string | null;
246
+ member_id: string | null;
247
+ };
248
+ expires_at: string;
249
+ accepted_at: string | null;
250
+ }[];
251
+ next_cursor: string | null;
252
+ }>;
253
+ revoke: (id: string, opts?: RequestOpts) => Promise<{
254
+ status: "pending" | "accepted" | "revoked" | "expired";
255
+ id: string;
256
+ created_at: string;
257
+ email: string;
258
+ role: "owner" | "admin" | "editor" | "viewer";
259
+ revoked_at: string | null;
260
+ invited_by: {
261
+ email: string | null;
262
+ member_id: string | null;
263
+ };
264
+ expires_at: string;
265
+ accepted_at: string | null;
266
+ }>;
267
+ accept: (body: RouteBody<"invites.accept">, opts?: RequestOpts) => Promise<{
268
+ workspace: {
269
+ id: string;
270
+ name: string;
271
+ created_at: string;
272
+ updated_at: string;
273
+ slug: string;
274
+ settings: {
275
+ asset_policy: "any" | "service_only";
276
+ default_locale: string;
277
+ locales: string[];
278
+ tracking_enabled: boolean;
279
+ default_timezone: string | null;
280
+ };
281
+ company_id: string | null;
282
+ role: "owner" | "admin" | "editor" | "viewer";
283
+ };
284
+ already_member: boolean;
285
+ }>;
286
+ };
287
+ apiKeys: {
288
+ list: (query?: RouteQuery<"apiKeys.list">, opts?: RequestOpts) => Promise<{
289
+ data: {
290
+ id: string;
291
+ name: string;
292
+ created_at: string;
293
+ scope: "send" | "full" | "read";
294
+ prefix: string;
295
+ last_used_at: string | null;
296
+ revoked_at: string | null;
297
+ }[];
298
+ next_cursor: string | null;
299
+ }>;
300
+ create: (body: RouteBody<"apiKeys.create">, opts?: RequestOpts) => Promise<{
301
+ key: string;
302
+ api_key: {
303
+ id: string;
304
+ name: string;
305
+ created_at: string;
306
+ scope: "send" | "full" | "read";
307
+ prefix: string;
308
+ last_used_at: string | null;
309
+ revoked_at: string | null;
310
+ };
311
+ }>;
312
+ revoke: (id: string, opts?: RequestOpts) => Promise<{
313
+ id: string;
314
+ name: string;
315
+ created_at: string;
316
+ scope: "send" | "full" | "read";
317
+ prefix: string;
318
+ last_used_at: string | null;
319
+ revoked_at: string | null;
320
+ }>;
321
+ };
322
+ auditLog: {
323
+ list: (query?: RouteQuery<"audit.list">, opts?: RequestOpts) => Promise<{
324
+ data: {
325
+ id: string;
326
+ details: Record<string, unknown>;
327
+ created_at: string;
328
+ action: "workspace.created" | "workspace.updated" | "workspace.company_changed" | "member.added" | "member.role_changed" | "member.removed" | "member.invited" | "invite.revoked" | "api_key.created" | "api_key.revoked" | "provider.created" | "provider.updated" | "provider.deleted" | "provider.events_registered" | "provider.events_secret_set" | "provider.bounces_halted" | "provider.anomaly_cleared" | "topic.created" | "topic.updated" | "template.created" | "template.updated" | "template.deleted" | "saved_section.created" | "saved_section.updated" | "saved_section.deleted" | "asset.uploaded" | "asset.imported" | "contact.erased" | "suppression.created" | "suppression.deleted" | "mailing.created" | "mailing.sent" | "mailing.paused" | "mailing.resumed" | "mailing.cancelled" | "mailing.retried" | "webhook.created" | "webhook.updated" | "webhook.deleted" | "webhook.secret_rotated" | "webhook.redelivered" | "contact.unsubscribed" | "tag.created" | "tag.deleted" | "tag.assigned" | "tag.unassigned" | "contact_property.created" | "contact_property.deleted" | "segment.created" | "segment.updated" | "segment.deleted" | "signup_form.created" | "signup_form.updated" | "signup_form.deleted" | "contact.subscribed" | "import.created" | "import.mapped" | "import.committed" | "import.cancelled" | "import.finished" | "mailing.scheduled" | "mailing.unscheduled" | "mailing.schedule_failed" | "mailing.ab_test_updated" | "mailing.ab_winner_selected" | "tracking.updated" | "billing.checkout_started" | "billing.subscription_changed" | "billing.exemption_changed" | "automation.created" | "automation.updated" | "automation.published" | "automation.paused" | "automation.resumed" | "automation.archived" | "automation.deleted" | "automation.duplicated" | "automation.enrolled" | "automation.run_ended" | "event.recorded";
329
+ actor: {
330
+ type: "member";
331
+ subject: string;
332
+ member_id: string;
333
+ } | {
334
+ type: "api_key";
335
+ api_key_id: string;
336
+ } | {
337
+ type: "system";
338
+ reason: string;
339
+ };
340
+ target_type: string;
341
+ target_id: string | null;
342
+ }[];
343
+ next_cursor: string | null;
344
+ }>;
345
+ };
346
+ templates: {
347
+ list: (query?: RouteQuery<"templates.list">, opts?: RequestOpts) => Promise<{
348
+ data: {
349
+ id: string;
350
+ version: number;
351
+ name: string;
352
+ description: string | null;
353
+ thumbnail_url: string | null;
354
+ archived_at: string | null;
355
+ created_at: string;
356
+ updated_at: string;
357
+ }[];
358
+ next_cursor: string | null;
359
+ }>;
360
+ create: (body: RouteBody<"templates.create">, opts?: RequestOpts) => Promise<{
361
+ id: string;
362
+ version: number;
363
+ name: string;
364
+ description: string | null;
365
+ document: {
366
+ version: "1.0" | "1.1";
367
+ metadata: Record<string, unknown>;
368
+ sections: Record<string, unknown>[];
369
+ } & {
370
+ [k: string]: unknown;
371
+ };
372
+ thumbnail_url: string | null;
373
+ archived_at: string | null;
374
+ created_at: string;
375
+ updated_at: string;
376
+ }>;
377
+ get: (id: string, opts?: RequestOpts) => Promise<{
378
+ id: string;
379
+ version: number;
380
+ name: string;
381
+ description: string | null;
382
+ document: {
383
+ version: "1.0" | "1.1";
384
+ metadata: Record<string, unknown>;
385
+ sections: Record<string, unknown>[];
386
+ } & {
387
+ [k: string]: unknown;
388
+ };
389
+ thumbnail_url: string | null;
390
+ archived_at: string | null;
391
+ created_at: string;
392
+ updated_at: string;
393
+ }>;
394
+ update: (id: string, body: RouteBody<"templates.update">, opts?: RequestOpts) => Promise<{
395
+ id: string;
396
+ version: number;
397
+ name: string;
398
+ description: string | null;
399
+ document: {
400
+ version: "1.0" | "1.1";
401
+ metadata: Record<string, unknown>;
402
+ sections: Record<string, unknown>[];
403
+ } & {
404
+ [k: string]: unknown;
405
+ };
406
+ thumbnail_url: string | null;
407
+ archived_at: string | null;
408
+ created_at: string;
409
+ updated_at: string;
410
+ }>;
411
+ delete: (id: string, opts?: RequestOpts) => Promise<{
412
+ ok: true;
413
+ }>;
414
+ versions: (id: string, query?: RouteQuery<"templates.versions">, opts?: RequestOpts) => Promise<{
415
+ data: {
416
+ version: number;
417
+ document: {
418
+ version: "1.0" | "1.1";
419
+ metadata: Record<string, unknown>;
420
+ sections: Record<string, unknown>[];
421
+ } & {
422
+ [k: string]: unknown;
423
+ };
424
+ created_at: string;
425
+ created_by: string | null;
426
+ template_id: string;
427
+ }[];
428
+ next_cursor: string | null;
429
+ }>;
430
+ version: (id: string, version: number, opts?: RequestOpts) => Promise<{
431
+ version: number;
432
+ document: {
433
+ version: "1.0" | "1.1";
434
+ metadata: Record<string, unknown>;
435
+ sections: Record<string, unknown>[];
436
+ } & {
437
+ [k: string]: unknown;
438
+ };
439
+ created_at: string;
440
+ created_by: string | null;
441
+ template_id: string;
442
+ }>;
443
+ compile: (id: string, body?: RouteBody<"templates.compile">, opts?: RequestOpts) => Promise<{
444
+ mjml: string;
445
+ html: string;
446
+ warnings: {
447
+ message: string;
448
+ path?: string | undefined;
449
+ line?: number | undefined;
450
+ }[];
451
+ errors: {
452
+ message: string;
453
+ path?: string | undefined;
454
+ line?: number | undefined;
455
+ }[];
456
+ }>;
457
+ /**
458
+ * Creates a template (version 1) from MJML. What the editor cannot hold
459
+ * as a block is kept as compiled HTML and reported in `warnings`; broken
460
+ * MJML is `invalid_mjml` with the line and column in `details`.
461
+ */
462
+ import: (body: RouteBody<"templates.import">, opts?: RequestOpts) => Promise<{
463
+ warnings: {
464
+ code: string;
465
+ path: string;
466
+ message: string;
467
+ severity: "info" | "warning";
468
+ line?: number | undefined;
469
+ fragment?: string | undefined;
470
+ }[];
471
+ template: {
472
+ id: string;
473
+ version: number;
474
+ name: string;
475
+ description: string | null;
476
+ document: {
477
+ version: "1.0" | "1.1";
478
+ metadata: Record<string, unknown>;
479
+ sections: Record<string, unknown>[];
480
+ } & {
481
+ [k: string]: unknown;
482
+ };
483
+ thumbnail_url: string | null;
484
+ archived_at: string | null;
485
+ created_at: string;
486
+ updated_at: string;
487
+ };
488
+ imported_assets: {
489
+ url: string;
490
+ source_url: string;
491
+ asset_id: string;
492
+ }[];
493
+ }>;
494
+ /** What `import` would create, compiled, without saving anything. */
495
+ importPreview: (body: RouteBody<"templates.importPreview">, opts?: RequestOpts) => Promise<{
496
+ document: {
497
+ version: "1.0" | "1.1";
498
+ metadata: Record<string, unknown>;
499
+ sections: Record<string, unknown>[];
500
+ } & {
501
+ [k: string]: unknown;
502
+ };
503
+ warnings: {
504
+ code: string;
505
+ path: string;
506
+ message: string;
507
+ severity: "info" | "warning";
508
+ line?: number | undefined;
509
+ fragment?: string | undefined;
510
+ }[];
511
+ compiled: {
512
+ mjml: string;
513
+ html: string;
514
+ warnings: {
515
+ message: string;
516
+ path?: string | undefined;
517
+ line?: number | undefined;
518
+ }[];
519
+ errors: {
520
+ message: string;
521
+ path?: string | undefined;
522
+ line?: number | undefined;
523
+ }[];
524
+ };
525
+ remote_images: {
526
+ url: string;
527
+ where: string;
528
+ }[];
529
+ asset_policy: "any" | "service_only";
530
+ }>;
531
+ /**
532
+ * The template (or a past `version`) as an `.mjml` or `.html` file, asset
533
+ * addresses absolute. Never refused for the asset policy: see `warnings`.
534
+ */
535
+ export: (id: string, query: RouteQuery<"templates.export">, opts?: RequestOpts) => Promise<ExportedFile>;
536
+ };
537
+ /**
538
+ * Saved sections: one section of a document kept under a name, so a footer
539
+ * built once can be dropped into any other template of the workspace.
540
+ *
541
+ * A stamp, not a live partial: inserting copies, and `update` overwriting
542
+ * the saved copy leaves every template that already holds one untouched.
543
+ * A workspace keeps at most `MAX_SAVED_SECTIONS` of them, and a name is
544
+ * unique within it, so a duplicate is `already_exists` rather than a
545
+ * silent overwrite.
546
+ */
547
+ savedSections: {
548
+ list: (query?: RouteQuery<"savedSections.list">, opts?: RequestOpts) => Promise<{
549
+ data: {
550
+ id: string;
551
+ name: string;
552
+ description: string | null;
553
+ created_at: string;
554
+ updated_at: string;
555
+ section: Record<string, unknown>;
556
+ created_by: string | null;
557
+ }[];
558
+ next_cursor: string | null;
559
+ }>;
560
+ create: (body: RouteBody<"savedSections.create">, opts?: RequestOpts) => Promise<{
561
+ id: string;
562
+ name: string;
563
+ description: string | null;
564
+ created_at: string;
565
+ updated_at: string;
566
+ section: Record<string, unknown>;
567
+ created_by: string | null;
568
+ }>;
569
+ update: (id: string, body: RouteBody<"savedSections.update">, opts?: RequestOpts) => Promise<{
570
+ id: string;
571
+ name: string;
572
+ description: string | null;
573
+ created_at: string;
574
+ updated_at: string;
575
+ section: Record<string, unknown>;
576
+ created_by: string | null;
577
+ }>;
578
+ delete: (id: string, opts?: RequestOpts) => Promise<{
579
+ ok: true;
580
+ }>;
581
+ };
582
+ /** Compiles an unsaved document (the editor's live preview), not a saved template. */
583
+ compile: (body: RouteBody<"compile">, opts?: RequestOpts) => Promise<{
584
+ mjml: string;
585
+ html: string;
586
+ warnings: {
587
+ message: string;
588
+ path?: string | undefined;
589
+ line?: number | undefined;
590
+ }[];
591
+ errors: {
592
+ message: string;
593
+ path?: string | undefined;
594
+ line?: number | undefined;
595
+ }[];
596
+ }>;
597
+ assets: {
598
+ /** `file` must be a `Blob` (edge-safe): wrap a Node `Buffer` with `new Blob([buffer])`. */
599
+ upload: (file: Blob, filename?: string, opts?: RequestOpts) => Promise<{
600
+ id: string;
601
+ created_at: string;
602
+ url: string;
603
+ content_type: "image/png" | "image/jpeg" | "image/gif" | "image/webp";
604
+ size_bytes: number;
605
+ width: number | null;
606
+ height: number | null;
607
+ filename: string;
608
+ }>;
609
+ /**
610
+ * Copies a remote image into the workspace's assets and answers with the
611
+ * new asset, whose `url` is the service's own. The workspace setting
612
+ * `asset_policy: 'service_only'` accepts only such addresses in a mail.
613
+ */
614
+ import: (body: RouteBody<"assets.import">, opts?: RequestOpts) => Promise<{
615
+ id: string;
616
+ created_at: string;
617
+ url: string;
618
+ content_type: "image/png" | "image/jpeg" | "image/gif" | "image/webp";
619
+ size_bytes: number;
620
+ width: number | null;
621
+ height: number | null;
622
+ filename: string;
623
+ }>;
624
+ get: (id: string, opts?: RequestOpts) => Promise<{
625
+ id: string;
626
+ created_at: string;
627
+ url: string;
628
+ content_type: "image/png" | "image/jpeg" | "image/gif" | "image/webp";
629
+ size_bytes: number;
630
+ width: number | null;
631
+ height: number | null;
632
+ filename: string;
633
+ }>;
634
+ };
635
+ providers: {
636
+ list: (query?: RouteQuery<"providers.list">, opts?: RequestOpts) => Promise<{
637
+ data: ({
638
+ id: string;
639
+ name: string;
640
+ created_at: string;
641
+ updated_at: string;
642
+ kind: "smtp";
643
+ config: {
644
+ host: string;
645
+ port: number;
646
+ security: "tls" | "starttls";
647
+ username: string;
648
+ };
649
+ has_secret: boolean;
650
+ rejections: {
651
+ last_error: string | null;
652
+ count: number;
653
+ last_at: string | null;
654
+ anomaly: {
655
+ at: string;
656
+ reason: string;
657
+ mailing_id: string | null;
658
+ sample: string;
659
+ scope: "mailing" | "provider";
660
+ blocking: boolean;
661
+ } | null;
662
+ };
663
+ from_name: string;
664
+ from_email: string;
665
+ reply_to: string | null;
666
+ policy: {
667
+ daily_recipient_budget: number;
668
+ min_interval_ms: number;
669
+ max_recipients_per_message: number;
670
+ };
671
+ } | {
672
+ id: string;
673
+ name: string;
674
+ created_at: string;
675
+ updated_at: string;
676
+ kind: "resend";
677
+ config: {};
678
+ has_secret: boolean;
679
+ rejections: {
680
+ last_error: string | null;
681
+ count: number;
682
+ last_at: string | null;
683
+ anomaly: {
684
+ at: string;
685
+ reason: string;
686
+ mailing_id: string | null;
687
+ sample: string;
688
+ scope: "mailing" | "provider";
689
+ blocking: boolean;
690
+ } | null;
691
+ };
692
+ from_name: string;
693
+ from_email: string;
694
+ reply_to: string | null;
695
+ policy: {
696
+ daily_recipient_budget: number;
697
+ min_interval_ms: number;
698
+ max_recipients_per_message: number;
699
+ };
700
+ events: {
701
+ status: "active" | "needs_secret";
702
+ error: string | null;
703
+ url: string;
704
+ source: "manual" | "automatic" | null;
705
+ unmatched: number;
706
+ };
707
+ })[];
708
+ next_cursor: string | null;
709
+ }>;
710
+ create: (body: RouteBody<"providers.create">, opts?: RequestOpts) => Promise<{
711
+ id: string;
712
+ name: string;
713
+ created_at: string;
714
+ updated_at: string;
715
+ kind: "smtp";
716
+ config: {
717
+ host: string;
718
+ port: number;
719
+ security: "tls" | "starttls";
720
+ username: string;
721
+ };
722
+ has_secret: boolean;
723
+ rejections: {
724
+ last_error: string | null;
725
+ count: number;
726
+ last_at: string | null;
727
+ anomaly: {
728
+ at: string;
729
+ reason: string;
730
+ mailing_id: string | null;
731
+ sample: string;
732
+ scope: "mailing" | "provider";
733
+ blocking: boolean;
734
+ } | null;
735
+ };
736
+ from_name: string;
737
+ from_email: string;
738
+ reply_to: string | null;
739
+ policy: {
740
+ daily_recipient_budget: number;
741
+ min_interval_ms: number;
742
+ max_recipients_per_message: number;
743
+ };
744
+ } | {
745
+ id: string;
746
+ name: string;
747
+ created_at: string;
748
+ updated_at: string;
749
+ kind: "resend";
750
+ config: {};
751
+ has_secret: boolean;
752
+ rejections: {
753
+ last_error: string | null;
754
+ count: number;
755
+ last_at: string | null;
756
+ anomaly: {
757
+ at: string;
758
+ reason: string;
759
+ mailing_id: string | null;
760
+ sample: string;
761
+ scope: "mailing" | "provider";
762
+ blocking: boolean;
763
+ } | null;
764
+ };
765
+ from_name: string;
766
+ from_email: string;
767
+ reply_to: string | null;
768
+ policy: {
769
+ daily_recipient_budget: number;
770
+ min_interval_ms: number;
771
+ max_recipients_per_message: number;
772
+ };
773
+ events: {
774
+ status: "active" | "needs_secret";
775
+ error: string | null;
776
+ url: string;
777
+ source: "manual" | "automatic" | null;
778
+ unmatched: number;
779
+ };
780
+ }>;
781
+ get: (id: string, opts?: RequestOpts) => Promise<{
782
+ id: string;
783
+ name: string;
784
+ created_at: string;
785
+ updated_at: string;
786
+ kind: "smtp";
787
+ config: {
788
+ host: string;
789
+ port: number;
790
+ security: "tls" | "starttls";
791
+ username: string;
792
+ };
793
+ has_secret: boolean;
794
+ rejections: {
795
+ last_error: string | null;
796
+ count: number;
797
+ last_at: string | null;
798
+ anomaly: {
799
+ at: string;
800
+ reason: string;
801
+ mailing_id: string | null;
802
+ sample: string;
803
+ scope: "mailing" | "provider";
804
+ blocking: boolean;
805
+ } | null;
806
+ };
807
+ from_name: string;
808
+ from_email: string;
809
+ reply_to: string | null;
810
+ policy: {
811
+ daily_recipient_budget: number;
812
+ min_interval_ms: number;
813
+ max_recipients_per_message: number;
814
+ };
815
+ } | {
816
+ id: string;
817
+ name: string;
818
+ created_at: string;
819
+ updated_at: string;
820
+ kind: "resend";
821
+ config: {};
822
+ has_secret: boolean;
823
+ rejections: {
824
+ last_error: string | null;
825
+ count: number;
826
+ last_at: string | null;
827
+ anomaly: {
828
+ at: string;
829
+ reason: string;
830
+ mailing_id: string | null;
831
+ sample: string;
832
+ scope: "mailing" | "provider";
833
+ blocking: boolean;
834
+ } | null;
835
+ };
836
+ from_name: string;
837
+ from_email: string;
838
+ reply_to: string | null;
839
+ policy: {
840
+ daily_recipient_budget: number;
841
+ min_interval_ms: number;
842
+ max_recipients_per_message: number;
843
+ };
844
+ events: {
845
+ status: "active" | "needs_secret";
846
+ error: string | null;
847
+ url: string;
848
+ source: "manual" | "automatic" | null;
849
+ unmatched: number;
850
+ };
851
+ }>;
852
+ update: (id: string, body: RouteBody<"providers.update">, opts?: RequestOpts) => Promise<{
853
+ id: string;
854
+ name: string;
855
+ created_at: string;
856
+ updated_at: string;
857
+ kind: "smtp";
858
+ config: {
859
+ host: string;
860
+ port: number;
861
+ security: "tls" | "starttls";
862
+ username: string;
863
+ };
864
+ has_secret: boolean;
865
+ rejections: {
866
+ last_error: string | null;
867
+ count: number;
868
+ last_at: string | null;
869
+ anomaly: {
870
+ at: string;
871
+ reason: string;
872
+ mailing_id: string | null;
873
+ sample: string;
874
+ scope: "mailing" | "provider";
875
+ blocking: boolean;
876
+ } | null;
877
+ };
878
+ from_name: string;
879
+ from_email: string;
880
+ reply_to: string | null;
881
+ policy: {
882
+ daily_recipient_budget: number;
883
+ min_interval_ms: number;
884
+ max_recipients_per_message: number;
885
+ };
886
+ } | {
887
+ id: string;
888
+ name: string;
889
+ created_at: string;
890
+ updated_at: string;
891
+ kind: "resend";
892
+ config: {};
893
+ has_secret: boolean;
894
+ rejections: {
895
+ last_error: string | null;
896
+ count: number;
897
+ last_at: string | null;
898
+ anomaly: {
899
+ at: string;
900
+ reason: string;
901
+ mailing_id: string | null;
902
+ sample: string;
903
+ scope: "mailing" | "provider";
904
+ blocking: boolean;
905
+ } | null;
906
+ };
907
+ from_name: string;
908
+ from_email: string;
909
+ reply_to: string | null;
910
+ policy: {
911
+ daily_recipient_budget: number;
912
+ min_interval_ms: number;
913
+ max_recipients_per_message: number;
914
+ };
915
+ events: {
916
+ status: "active" | "needs_secret";
917
+ error: string | null;
918
+ url: string;
919
+ source: "manual" | "automatic" | null;
920
+ unmatched: number;
921
+ };
922
+ }>;
923
+ delete: (id: string, opts?: RequestOpts) => Promise<{
924
+ ok: true;
925
+ }>;
926
+ verify: (id: string, opts?: RequestOpts) => Promise<{
927
+ ok: boolean;
928
+ error: string | null;
929
+ }>;
930
+ usage: (id: string, opts?: RequestOpts) => Promise<{
931
+ provider_id: string;
932
+ recipients_last_24h: number;
933
+ remaining_budget: number;
934
+ next_capacity_at: string | null;
935
+ }>;
936
+ /** Clears the provider's bounce anomaly, reopening bounce blocking, test sends and mailing starts. */
937
+ clearAnomaly: (id: string, opts?: RequestOpts) => Promise<{
938
+ id: string;
939
+ name: string;
940
+ created_at: string;
941
+ updated_at: string;
942
+ kind: "smtp";
943
+ config: {
944
+ host: string;
945
+ port: number;
946
+ security: "tls" | "starttls";
947
+ username: string;
948
+ };
949
+ has_secret: boolean;
950
+ rejections: {
951
+ last_error: string | null;
952
+ count: number;
953
+ last_at: string | null;
954
+ anomaly: {
955
+ at: string;
956
+ reason: string;
957
+ mailing_id: string | null;
958
+ sample: string;
959
+ scope: "mailing" | "provider";
960
+ blocking: boolean;
961
+ } | null;
962
+ };
963
+ from_name: string;
964
+ from_email: string;
965
+ reply_to: string | null;
966
+ policy: {
967
+ daily_recipient_budget: number;
968
+ min_interval_ms: number;
969
+ max_recipients_per_message: number;
970
+ };
971
+ } | {
972
+ id: string;
973
+ name: string;
974
+ created_at: string;
975
+ updated_at: string;
976
+ kind: "resend";
977
+ config: {};
978
+ has_secret: boolean;
979
+ rejections: {
980
+ last_error: string | null;
981
+ count: number;
982
+ last_at: string | null;
983
+ anomaly: {
984
+ at: string;
985
+ reason: string;
986
+ mailing_id: string | null;
987
+ sample: string;
988
+ scope: "mailing" | "provider";
989
+ blocking: boolean;
990
+ } | null;
991
+ };
992
+ from_name: string;
993
+ from_email: string;
994
+ reply_to: string | null;
995
+ policy: {
996
+ daily_recipient_budget: number;
997
+ min_interval_ms: number;
998
+ max_recipients_per_message: number;
999
+ };
1000
+ events: {
1001
+ status: "active" | "needs_secret";
1002
+ error: string | null;
1003
+ url: string;
1004
+ source: "manual" | "automatic" | null;
1005
+ unmatched: number;
1006
+ };
1007
+ }>;
1008
+ /** Stores the signing secret of a Resend webhook registered by hand, so bounces and complaints are accepted. */
1009
+ setEventsSecret: (id: string, body: RouteBody<"providers.setEventsSecret">, opts?: RequestOpts) => Promise<{
1010
+ id: string;
1011
+ name: string;
1012
+ created_at: string;
1013
+ updated_at: string;
1014
+ kind: "smtp";
1015
+ config: {
1016
+ host: string;
1017
+ port: number;
1018
+ security: "tls" | "starttls";
1019
+ username: string;
1020
+ };
1021
+ has_secret: boolean;
1022
+ rejections: {
1023
+ last_error: string | null;
1024
+ count: number;
1025
+ last_at: string | null;
1026
+ anomaly: {
1027
+ at: string;
1028
+ reason: string;
1029
+ mailing_id: string | null;
1030
+ sample: string;
1031
+ scope: "mailing" | "provider";
1032
+ blocking: boolean;
1033
+ } | null;
1034
+ };
1035
+ from_name: string;
1036
+ from_email: string;
1037
+ reply_to: string | null;
1038
+ policy: {
1039
+ daily_recipient_budget: number;
1040
+ min_interval_ms: number;
1041
+ max_recipients_per_message: number;
1042
+ };
1043
+ } | {
1044
+ id: string;
1045
+ name: string;
1046
+ created_at: string;
1047
+ updated_at: string;
1048
+ kind: "resend";
1049
+ config: {};
1050
+ has_secret: boolean;
1051
+ rejections: {
1052
+ last_error: string | null;
1053
+ count: number;
1054
+ last_at: string | null;
1055
+ anomaly: {
1056
+ at: string;
1057
+ reason: string;
1058
+ mailing_id: string | null;
1059
+ sample: string;
1060
+ scope: "mailing" | "provider";
1061
+ blocking: boolean;
1062
+ } | null;
1063
+ };
1064
+ from_name: string;
1065
+ from_email: string;
1066
+ reply_to: string | null;
1067
+ policy: {
1068
+ daily_recipient_budget: number;
1069
+ min_interval_ms: number;
1070
+ max_recipients_per_message: number;
1071
+ };
1072
+ events: {
1073
+ status: "active" | "needs_secret";
1074
+ error: string | null;
1075
+ url: string;
1076
+ source: "manual" | "automatic" | null;
1077
+ unmatched: number;
1078
+ };
1079
+ }>;
1080
+ };
1081
+ topics: {
1082
+ list: (query?: RouteQuery<"topics.list">, opts?: RequestOpts) => Promise<{
1083
+ data: {
1084
+ id: string;
1085
+ name: string;
1086
+ description: string | null;
1087
+ created_at: string;
1088
+ updated_at: string;
1089
+ slug: string;
1090
+ translations: Record<string, {
1091
+ name: string;
1092
+ description: string | null;
1093
+ }>;
1094
+ }[];
1095
+ next_cursor: string | null;
1096
+ }>;
1097
+ create: (body: RouteBody<"topics.create">, opts?: RequestOpts) => Promise<{
1098
+ id: string;
1099
+ name: string;
1100
+ description: string | null;
1101
+ created_at: string;
1102
+ updated_at: string;
1103
+ slug: string;
1104
+ translations: Record<string, {
1105
+ name: string;
1106
+ description: string | null;
1107
+ }>;
1108
+ }>;
1109
+ update: (id: string, body: RouteBody<"topics.update">, opts?: RequestOpts) => Promise<{
1110
+ id: string;
1111
+ name: string;
1112
+ description: string | null;
1113
+ created_at: string;
1114
+ updated_at: string;
1115
+ slug: string;
1116
+ translations: Record<string, {
1117
+ name: string;
1118
+ description: string | null;
1119
+ }>;
1120
+ }>;
1121
+ };
1122
+ contacts: {
1123
+ upsert: (body: RouteBody<"contacts.upsert">, opts?: RequestOpts) => Promise<{
1124
+ created: boolean;
1125
+ contact: {
1126
+ id: string;
1127
+ created_at: string;
1128
+ updated_at: string;
1129
+ email: string;
1130
+ external_id: string | null;
1131
+ first_name: string | null;
1132
+ last_name: string | null;
1133
+ locale: string | null;
1134
+ topics: string[];
1135
+ tags: string[];
1136
+ timezone: string | null;
1137
+ properties: Record<string, _marlinjai_mail_contract.JsonValue>;
1138
+ };
1139
+ }>;
1140
+ list: (query?: RouteQuery<"contacts.list">, opts?: RequestOpts) => Promise<{
1141
+ data: {
1142
+ id: string;
1143
+ created_at: string;
1144
+ updated_at: string;
1145
+ email: string;
1146
+ external_id: string | null;
1147
+ first_name: string | null;
1148
+ last_name: string | null;
1149
+ locale: string | null;
1150
+ topics: string[];
1151
+ tags: string[];
1152
+ timezone: string | null;
1153
+ properties: Record<string, _marlinjai_mail_contract.JsonValue>;
1154
+ }[];
1155
+ next_cursor: string | null;
1156
+ }>;
1157
+ get: (id: string, opts?: RequestOpts) => Promise<{
1158
+ id: string;
1159
+ created_at: string;
1160
+ updated_at: string;
1161
+ email: string;
1162
+ external_id: string | null;
1163
+ first_name: string | null;
1164
+ last_name: string | null;
1165
+ locale: string | null;
1166
+ topics: string[];
1167
+ tags: string[];
1168
+ timezone: string | null;
1169
+ properties: Record<string, _marlinjai_mail_contract.JsonValue>;
1170
+ }>;
1171
+ erase: (id: string, opts?: RequestOpts) => Promise<{
1172
+ ok: true;
1173
+ erased_messages: number;
1174
+ erased_recipients: number;
1175
+ suppressions_kept: number;
1176
+ }>;
1177
+ messages: (id: string, query?: RouteQuery<"contacts.messages">, opts?: RequestOpts) => Promise<{
1178
+ data: {
1179
+ id: string;
1180
+ error: string | null;
1181
+ created_at: string;
1182
+ subject: string;
1183
+ provider_id: string;
1184
+ to: string;
1185
+ provider_message_id: string | null;
1186
+ mailing_id: string | null;
1187
+ contact_id: string | null;
1188
+ recipient_id: string | null;
1189
+ outcome: "sent" | "failed";
1190
+ is_test: boolean;
1191
+ recipient_count: number;
1192
+ }[];
1193
+ next_cursor: string | null;
1194
+ }>;
1195
+ /** Every automation this person has been through, for the contact's own page. */
1196
+ automations: (id: string, query?: RouteQuery<"contacts.automations">, opts?: RequestOpts) => Promise<{
1197
+ data: {
1198
+ status: "failed" | "completed" | "active" | "exited" | "waiting";
1199
+ id: string;
1200
+ version: number;
1201
+ automation: {
1202
+ status: "archived" | "draft" | "paused" | "active";
1203
+ id: string;
1204
+ name: string;
1205
+ };
1206
+ automation_id: string;
1207
+ contact_id: string;
1208
+ email: string;
1209
+ last_error: string | null;
1210
+ external_id: string | null;
1211
+ current_step_id: string | null;
1212
+ next_action_at: string | null;
1213
+ wait_reason: "sending" | "delay" | "condition" | "quiet_hours" | "plan_limit" | null;
1214
+ end_reason: string | null;
1215
+ entered_at: string;
1216
+ ended_at: string | null;
1217
+ }[];
1218
+ next_cursor: string | null;
1219
+ }>;
1220
+ };
1221
+ suppressions: {
1222
+ list: (query?: RouteQuery<"suppressions.list">, opts?: RequestOpts) => Promise<{
1223
+ data: {
1224
+ id: string;
1225
+ reason: "manual" | "unsubscribed" | "bounced" | "complained";
1226
+ created_at: string;
1227
+ topic: string | null;
1228
+ email: string;
1229
+ source_message_id: string | null;
1230
+ note: string | null;
1231
+ }[];
1232
+ next_cursor: string | null;
1233
+ }>;
1234
+ create: (body: RouteBody<"suppressions.create">, opts?: RequestOpts) => Promise<{
1235
+ id: string;
1236
+ reason: "manual" | "unsubscribed" | "bounced" | "complained";
1237
+ created_at: string;
1238
+ topic: string | null;
1239
+ email: string;
1240
+ source_message_id: string | null;
1241
+ note: string | null;
1242
+ }>;
1243
+ delete: (id: string, opts?: RequestOpts) => Promise<{
1244
+ ok: true;
1245
+ }>;
1246
+ };
1247
+ mailings: {
1248
+ list: (query?: RouteQuery<"mailings.list">, opts?: RequestOpts) => Promise<{
1249
+ data: {
1250
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1251
+ id: string;
1252
+ metadata: Record<string, string>;
1253
+ name: string | null;
1254
+ created_at: string;
1255
+ updated_at: string;
1256
+ template_id: string | null;
1257
+ subject: string;
1258
+ kind: "broadcast" | "automation" | "notification";
1259
+ preheader: string | null;
1260
+ topic: string;
1261
+ provider_id: string;
1262
+ counts: {
1263
+ sending: number;
1264
+ sent: number;
1265
+ total: number;
1266
+ queued: number;
1267
+ failed: number;
1268
+ skipped: number;
1269
+ };
1270
+ scheduled_at: string | null;
1271
+ ab_test: {
1272
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1273
+ variants: {
1274
+ key: string;
1275
+ subject: string | null;
1276
+ has_document: boolean;
1277
+ }[];
1278
+ test_fraction: number;
1279
+ winner_metric: "opens" | "clicks" | "manual";
1280
+ decide_after_minutes: number | null;
1281
+ decide_at: string | null;
1282
+ winner: string | null;
1283
+ decided_by: "manual" | "metric" | null;
1284
+ decided_at: string | null;
1285
+ } | null;
1286
+ started_at: string | null;
1287
+ finished_at: string | null;
1288
+ pause_reason: string | null;
1289
+ }[];
1290
+ next_cursor: string | null;
1291
+ }>;
1292
+ create: (body: RouteBody<"mailings.create">, opts?: RequestOpts) => Promise<{
1293
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1294
+ id: string;
1295
+ metadata: Record<string, string>;
1296
+ name: string | null;
1297
+ document: {
1298
+ version: "1.0" | "1.1";
1299
+ metadata: Record<string, unknown>;
1300
+ sections: Record<string, unknown>[];
1301
+ } & {
1302
+ [k: string]: unknown;
1303
+ };
1304
+ created_at: string;
1305
+ updated_at: string;
1306
+ template_id: string | null;
1307
+ subject: string;
1308
+ kind: "broadcast" | "automation" | "notification";
1309
+ preheader: string | null;
1310
+ topic: string;
1311
+ provider_id: string;
1312
+ counts: {
1313
+ sending: number;
1314
+ sent: number;
1315
+ total: number;
1316
+ queued: number;
1317
+ failed: number;
1318
+ skipped: number;
1319
+ };
1320
+ scheduled_at: string | null;
1321
+ ab_test: {
1322
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1323
+ variants: {
1324
+ key: string;
1325
+ subject: string | null;
1326
+ has_document: boolean;
1327
+ }[];
1328
+ test_fraction: number;
1329
+ winner_metric: "opens" | "clicks" | "manual";
1330
+ decide_after_minutes: number | null;
1331
+ decide_at: string | null;
1332
+ winner: string | null;
1333
+ decided_by: "manual" | "metric" | null;
1334
+ decided_at: string | null;
1335
+ } | null;
1336
+ started_at: string | null;
1337
+ finished_at: string | null;
1338
+ pause_reason: string | null;
1339
+ }>;
1340
+ get: (id: string, opts?: RequestOpts) => Promise<{
1341
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1342
+ id: string;
1343
+ metadata: Record<string, string>;
1344
+ name: string | null;
1345
+ document: {
1346
+ version: "1.0" | "1.1";
1347
+ metadata: Record<string, unknown>;
1348
+ sections: Record<string, unknown>[];
1349
+ } & {
1350
+ [k: string]: unknown;
1351
+ };
1352
+ created_at: string;
1353
+ updated_at: string;
1354
+ template_id: string | null;
1355
+ subject: string;
1356
+ kind: "broadcast" | "automation" | "notification";
1357
+ preheader: string | null;
1358
+ topic: string;
1359
+ provider_id: string;
1360
+ counts: {
1361
+ sending: number;
1362
+ sent: number;
1363
+ total: number;
1364
+ queued: number;
1365
+ failed: number;
1366
+ skipped: number;
1367
+ };
1368
+ scheduled_at: string | null;
1369
+ ab_test: {
1370
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1371
+ variants: {
1372
+ key: string;
1373
+ subject: string | null;
1374
+ has_document: boolean;
1375
+ }[];
1376
+ test_fraction: number;
1377
+ winner_metric: "opens" | "clicks" | "manual";
1378
+ decide_after_minutes: number | null;
1379
+ decide_at: string | null;
1380
+ winner: string | null;
1381
+ decided_by: "manual" | "metric" | null;
1382
+ decided_at: string | null;
1383
+ } | null;
1384
+ started_at: string | null;
1385
+ finished_at: string | null;
1386
+ pause_reason: string | null;
1387
+ }>;
1388
+ /** The mailing's content snapshot as an `.mjml` or `.html` file, like `templates.export`. */
1389
+ export: (id: string, query: RouteQuery<"mailings.export">, opts?: RequestOpts) => Promise<ExportedFile>;
1390
+ update: (id: string, body: RouteBody<"mailings.update">, opts?: RequestOpts) => Promise<{
1391
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1392
+ id: string;
1393
+ metadata: Record<string, string>;
1394
+ name: string | null;
1395
+ document: {
1396
+ version: "1.0" | "1.1";
1397
+ metadata: Record<string, unknown>;
1398
+ sections: Record<string, unknown>[];
1399
+ } & {
1400
+ [k: string]: unknown;
1401
+ };
1402
+ created_at: string;
1403
+ updated_at: string;
1404
+ template_id: string | null;
1405
+ subject: string;
1406
+ kind: "broadcast" | "automation" | "notification";
1407
+ preheader: string | null;
1408
+ topic: string;
1409
+ provider_id: string;
1410
+ counts: {
1411
+ sending: number;
1412
+ sent: number;
1413
+ total: number;
1414
+ queued: number;
1415
+ failed: number;
1416
+ skipped: number;
1417
+ };
1418
+ scheduled_at: string | null;
1419
+ ab_test: {
1420
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1421
+ variants: {
1422
+ key: string;
1423
+ subject: string | null;
1424
+ has_document: boolean;
1425
+ }[];
1426
+ test_fraction: number;
1427
+ winner_metric: "opens" | "clicks" | "manual";
1428
+ decide_after_minutes: number | null;
1429
+ decide_at: string | null;
1430
+ winner: string | null;
1431
+ decided_by: "manual" | "metric" | null;
1432
+ decided_at: string | null;
1433
+ } | null;
1434
+ started_at: string | null;
1435
+ finished_at: string | null;
1436
+ pause_reason: string | null;
1437
+ }>;
1438
+ addRecipients: (id: string, body: RouteBody<"mailings.addRecipients">, opts?: RequestOpts) => Promise<{
1439
+ added: number;
1440
+ already_present: number;
1441
+ rejected: {
1442
+ reason: "unknown_contact" | "duplicate_in_batch";
1443
+ index: number;
1444
+ }[];
1445
+ }>;
1446
+ listRecipients: (id: string, query?: RouteQuery<"mailings.listRecipients">, opts?: RequestOpts) => Promise<{
1447
+ data: {
1448
+ status: "sending" | "sent" | "queued" | "failed" | "skipped";
1449
+ id: string;
1450
+ created_at: string;
1451
+ updated_at: string;
1452
+ merge: Record<string, _marlinjai_mail_contract.JsonValue>;
1453
+ message_id: string | null;
1454
+ mailing_id: string;
1455
+ contact_id: string | null;
1456
+ email: string;
1457
+ skip_reason: "cancelled" | "suppressed" | "not_subscribed" | "contact_erased" | "outcome_unknown" | null;
1458
+ attempts: number;
1459
+ last_error: string | null;
1460
+ }[];
1461
+ next_cursor: string | null;
1462
+ }>;
1463
+ test: (id: string, body: RouteBody<"mailings.test">, opts?: RequestOpts) => Promise<{
1464
+ message_id: string;
1465
+ provider_message_id: string | null;
1466
+ }>;
1467
+ send: (id: string, opts?: RequestOpts) => Promise<{
1468
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1469
+ id: string;
1470
+ metadata: Record<string, string>;
1471
+ name: string | null;
1472
+ document: {
1473
+ version: "1.0" | "1.1";
1474
+ metadata: Record<string, unknown>;
1475
+ sections: Record<string, unknown>[];
1476
+ } & {
1477
+ [k: string]: unknown;
1478
+ };
1479
+ created_at: string;
1480
+ updated_at: string;
1481
+ template_id: string | null;
1482
+ subject: string;
1483
+ kind: "broadcast" | "automation" | "notification";
1484
+ preheader: string | null;
1485
+ topic: string;
1486
+ provider_id: string;
1487
+ counts: {
1488
+ sending: number;
1489
+ sent: number;
1490
+ total: number;
1491
+ queued: number;
1492
+ failed: number;
1493
+ skipped: number;
1494
+ };
1495
+ scheduled_at: string | null;
1496
+ ab_test: {
1497
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1498
+ variants: {
1499
+ key: string;
1500
+ subject: string | null;
1501
+ has_document: boolean;
1502
+ }[];
1503
+ test_fraction: number;
1504
+ winner_metric: "opens" | "clicks" | "manual";
1505
+ decide_after_minutes: number | null;
1506
+ decide_at: string | null;
1507
+ winner: string | null;
1508
+ decided_by: "manual" | "metric" | null;
1509
+ decided_at: string | null;
1510
+ } | null;
1511
+ started_at: string | null;
1512
+ finished_at: string | null;
1513
+ pause_reason: string | null;
1514
+ }>;
1515
+ pause: (id: string, opts?: RequestOpts) => Promise<{
1516
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1517
+ id: string;
1518
+ metadata: Record<string, string>;
1519
+ name: string | null;
1520
+ document: {
1521
+ version: "1.0" | "1.1";
1522
+ metadata: Record<string, unknown>;
1523
+ sections: Record<string, unknown>[];
1524
+ } & {
1525
+ [k: string]: unknown;
1526
+ };
1527
+ created_at: string;
1528
+ updated_at: string;
1529
+ template_id: string | null;
1530
+ subject: string;
1531
+ kind: "broadcast" | "automation" | "notification";
1532
+ preheader: string | null;
1533
+ topic: string;
1534
+ provider_id: string;
1535
+ counts: {
1536
+ sending: number;
1537
+ sent: number;
1538
+ total: number;
1539
+ queued: number;
1540
+ failed: number;
1541
+ skipped: number;
1542
+ };
1543
+ scheduled_at: string | null;
1544
+ ab_test: {
1545
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1546
+ variants: {
1547
+ key: string;
1548
+ subject: string | null;
1549
+ has_document: boolean;
1550
+ }[];
1551
+ test_fraction: number;
1552
+ winner_metric: "opens" | "clicks" | "manual";
1553
+ decide_after_minutes: number | null;
1554
+ decide_at: string | null;
1555
+ winner: string | null;
1556
+ decided_by: "manual" | "metric" | null;
1557
+ decided_at: string | null;
1558
+ } | null;
1559
+ started_at: string | null;
1560
+ finished_at: string | null;
1561
+ pause_reason: string | null;
1562
+ }>;
1563
+ resume: (id: string, opts?: RequestOpts) => Promise<{
1564
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1565
+ id: string;
1566
+ metadata: Record<string, string>;
1567
+ name: string | null;
1568
+ document: {
1569
+ version: "1.0" | "1.1";
1570
+ metadata: Record<string, unknown>;
1571
+ sections: Record<string, unknown>[];
1572
+ } & {
1573
+ [k: string]: unknown;
1574
+ };
1575
+ created_at: string;
1576
+ updated_at: string;
1577
+ template_id: string | null;
1578
+ subject: string;
1579
+ kind: "broadcast" | "automation" | "notification";
1580
+ preheader: string | null;
1581
+ topic: string;
1582
+ provider_id: string;
1583
+ counts: {
1584
+ sending: number;
1585
+ sent: number;
1586
+ total: number;
1587
+ queued: number;
1588
+ failed: number;
1589
+ skipped: number;
1590
+ };
1591
+ scheduled_at: string | null;
1592
+ ab_test: {
1593
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1594
+ variants: {
1595
+ key: string;
1596
+ subject: string | null;
1597
+ has_document: boolean;
1598
+ }[];
1599
+ test_fraction: number;
1600
+ winner_metric: "opens" | "clicks" | "manual";
1601
+ decide_after_minutes: number | null;
1602
+ decide_at: string | null;
1603
+ winner: string | null;
1604
+ decided_by: "manual" | "metric" | null;
1605
+ decided_at: string | null;
1606
+ } | null;
1607
+ started_at: string | null;
1608
+ finished_at: string | null;
1609
+ pause_reason: string | null;
1610
+ }>;
1611
+ cancel: (id: string, opts?: RequestOpts) => Promise<{
1612
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1613
+ id: string;
1614
+ metadata: Record<string, string>;
1615
+ name: string | null;
1616
+ document: {
1617
+ version: "1.0" | "1.1";
1618
+ metadata: Record<string, unknown>;
1619
+ sections: Record<string, unknown>[];
1620
+ } & {
1621
+ [k: string]: unknown;
1622
+ };
1623
+ created_at: string;
1624
+ updated_at: string;
1625
+ template_id: string | null;
1626
+ subject: string;
1627
+ kind: "broadcast" | "automation" | "notification";
1628
+ preheader: string | null;
1629
+ topic: string;
1630
+ provider_id: string;
1631
+ counts: {
1632
+ sending: number;
1633
+ sent: number;
1634
+ total: number;
1635
+ queued: number;
1636
+ failed: number;
1637
+ skipped: number;
1638
+ };
1639
+ scheduled_at: string | null;
1640
+ ab_test: {
1641
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1642
+ variants: {
1643
+ key: string;
1644
+ subject: string | null;
1645
+ has_document: boolean;
1646
+ }[];
1647
+ test_fraction: number;
1648
+ winner_metric: "opens" | "clicks" | "manual";
1649
+ decide_after_minutes: number | null;
1650
+ decide_at: string | null;
1651
+ winner: string | null;
1652
+ decided_by: "manual" | "metric" | null;
1653
+ decided_at: string | null;
1654
+ } | null;
1655
+ started_at: string | null;
1656
+ finished_at: string | null;
1657
+ pause_reason: string | null;
1658
+ }>;
1659
+ retryFailed: (id: string, body?: RouteBody<"mailings.retryFailed">, opts?: RequestOpts) => Promise<{
1660
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1661
+ id: string;
1662
+ metadata: Record<string, string>;
1663
+ name: string | null;
1664
+ document: {
1665
+ version: "1.0" | "1.1";
1666
+ metadata: Record<string, unknown>;
1667
+ sections: Record<string, unknown>[];
1668
+ } & {
1669
+ [k: string]: unknown;
1670
+ };
1671
+ created_at: string;
1672
+ updated_at: string;
1673
+ template_id: string | null;
1674
+ subject: string;
1675
+ kind: "broadcast" | "automation" | "notification";
1676
+ preheader: string | null;
1677
+ topic: string;
1678
+ provider_id: string;
1679
+ counts: {
1680
+ sending: number;
1681
+ sent: number;
1682
+ total: number;
1683
+ queued: number;
1684
+ failed: number;
1685
+ skipped: number;
1686
+ };
1687
+ scheduled_at: string | null;
1688
+ ab_test: {
1689
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1690
+ variants: {
1691
+ key: string;
1692
+ subject: string | null;
1693
+ has_document: boolean;
1694
+ }[];
1695
+ test_fraction: number;
1696
+ winner_metric: "opens" | "clicks" | "manual";
1697
+ decide_after_minutes: number | null;
1698
+ decide_at: string | null;
1699
+ winner: string | null;
1700
+ decided_by: "manual" | "metric" | null;
1701
+ decided_at: string | null;
1702
+ } | null;
1703
+ started_at: string | null;
1704
+ finished_at: string | null;
1705
+ pause_reason: string | null;
1706
+ }>;
1707
+ duplicate: (id: string, opts?: RequestOpts) => Promise<{
1708
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1709
+ id: string;
1710
+ metadata: Record<string, string>;
1711
+ name: string | null;
1712
+ document: {
1713
+ version: "1.0" | "1.1";
1714
+ metadata: Record<string, unknown>;
1715
+ sections: Record<string, unknown>[];
1716
+ } & {
1717
+ [k: string]: unknown;
1718
+ };
1719
+ created_at: string;
1720
+ updated_at: string;
1721
+ template_id: string | null;
1722
+ subject: string;
1723
+ kind: "broadcast" | "automation" | "notification";
1724
+ preheader: string | null;
1725
+ topic: string;
1726
+ provider_id: string;
1727
+ counts: {
1728
+ sending: number;
1729
+ sent: number;
1730
+ total: number;
1731
+ queued: number;
1732
+ failed: number;
1733
+ skipped: number;
1734
+ };
1735
+ scheduled_at: string | null;
1736
+ ab_test: {
1737
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1738
+ variants: {
1739
+ key: string;
1740
+ subject: string | null;
1741
+ has_document: boolean;
1742
+ }[];
1743
+ test_fraction: number;
1744
+ winner_metric: "opens" | "clicks" | "manual";
1745
+ decide_after_minutes: number | null;
1746
+ decide_at: string | null;
1747
+ winner: string | null;
1748
+ decided_by: "manual" | "metric" | null;
1749
+ decided_at: string | null;
1750
+ } | null;
1751
+ started_at: string | null;
1752
+ finished_at: string | null;
1753
+ pause_reason: string | null;
1754
+ }>;
1755
+ addSegment: (id: string, body: RouteBody<"mailings.addSegment">, opts?: RequestOpts) => Promise<{
1756
+ added: number;
1757
+ already_present: number;
1758
+ rejected: {
1759
+ reason: "unknown_contact" | "duplicate_in_batch";
1760
+ index: number;
1761
+ }[];
1762
+ }>;
1763
+ schedule: (id: string, body: RouteBody<"mailings.schedule">, opts?: RequestOpts) => Promise<{
1764
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1765
+ id: string;
1766
+ metadata: Record<string, string>;
1767
+ name: string | null;
1768
+ document: {
1769
+ version: "1.0" | "1.1";
1770
+ metadata: Record<string, unknown>;
1771
+ sections: Record<string, unknown>[];
1772
+ } & {
1773
+ [k: string]: unknown;
1774
+ };
1775
+ created_at: string;
1776
+ updated_at: string;
1777
+ template_id: string | null;
1778
+ subject: string;
1779
+ kind: "broadcast" | "automation" | "notification";
1780
+ preheader: string | null;
1781
+ topic: string;
1782
+ provider_id: string;
1783
+ counts: {
1784
+ sending: number;
1785
+ sent: number;
1786
+ total: number;
1787
+ queued: number;
1788
+ failed: number;
1789
+ skipped: number;
1790
+ };
1791
+ scheduled_at: string | null;
1792
+ ab_test: {
1793
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1794
+ variants: {
1795
+ key: string;
1796
+ subject: string | null;
1797
+ has_document: boolean;
1798
+ }[];
1799
+ test_fraction: number;
1800
+ winner_metric: "opens" | "clicks" | "manual";
1801
+ decide_after_minutes: number | null;
1802
+ decide_at: string | null;
1803
+ winner: string | null;
1804
+ decided_by: "manual" | "metric" | null;
1805
+ decided_at: string | null;
1806
+ } | null;
1807
+ started_at: string | null;
1808
+ finished_at: string | null;
1809
+ pause_reason: string | null;
1810
+ }>;
1811
+ unschedule: (id: string, opts?: RequestOpts) => Promise<{
1812
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1813
+ id: string;
1814
+ metadata: Record<string, string>;
1815
+ name: string | null;
1816
+ document: {
1817
+ version: "1.0" | "1.1";
1818
+ metadata: Record<string, unknown>;
1819
+ sections: Record<string, unknown>[];
1820
+ } & {
1821
+ [k: string]: unknown;
1822
+ };
1823
+ created_at: string;
1824
+ updated_at: string;
1825
+ template_id: string | null;
1826
+ subject: string;
1827
+ kind: "broadcast" | "automation" | "notification";
1828
+ preheader: string | null;
1829
+ topic: string;
1830
+ provider_id: string;
1831
+ counts: {
1832
+ sending: number;
1833
+ sent: number;
1834
+ total: number;
1835
+ queued: number;
1836
+ failed: number;
1837
+ skipped: number;
1838
+ };
1839
+ scheduled_at: string | null;
1840
+ ab_test: {
1841
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1842
+ variants: {
1843
+ key: string;
1844
+ subject: string | null;
1845
+ has_document: boolean;
1846
+ }[];
1847
+ test_fraction: number;
1848
+ winner_metric: "opens" | "clicks" | "manual";
1849
+ decide_after_minutes: number | null;
1850
+ decide_at: string | null;
1851
+ winner: string | null;
1852
+ decided_by: "manual" | "metric" | null;
1853
+ decided_at: string | null;
1854
+ } | null;
1855
+ started_at: string | null;
1856
+ finished_at: string | null;
1857
+ pause_reason: string | null;
1858
+ }>;
1859
+ setAbTest: (id: string, body: RouteBody<"mailings.setAbTest">, opts?: RequestOpts) => Promise<{
1860
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1861
+ id: string;
1862
+ metadata: Record<string, string>;
1863
+ name: string | null;
1864
+ document: {
1865
+ version: "1.0" | "1.1";
1866
+ metadata: Record<string, unknown>;
1867
+ sections: Record<string, unknown>[];
1868
+ } & {
1869
+ [k: string]: unknown;
1870
+ };
1871
+ created_at: string;
1872
+ updated_at: string;
1873
+ template_id: string | null;
1874
+ subject: string;
1875
+ kind: "broadcast" | "automation" | "notification";
1876
+ preheader: string | null;
1877
+ topic: string;
1878
+ provider_id: string;
1879
+ counts: {
1880
+ sending: number;
1881
+ sent: number;
1882
+ total: number;
1883
+ queued: number;
1884
+ failed: number;
1885
+ skipped: number;
1886
+ };
1887
+ scheduled_at: string | null;
1888
+ ab_test: {
1889
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1890
+ variants: {
1891
+ key: string;
1892
+ subject: string | null;
1893
+ has_document: boolean;
1894
+ }[];
1895
+ test_fraction: number;
1896
+ winner_metric: "opens" | "clicks" | "manual";
1897
+ decide_after_minutes: number | null;
1898
+ decide_at: string | null;
1899
+ winner: string | null;
1900
+ decided_by: "manual" | "metric" | null;
1901
+ decided_at: string | null;
1902
+ } | null;
1903
+ started_at: string | null;
1904
+ finished_at: string | null;
1905
+ pause_reason: string | null;
1906
+ }>;
1907
+ clearAbTest: (id: string, opts?: RequestOpts) => Promise<{
1908
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1909
+ id: string;
1910
+ metadata: Record<string, string>;
1911
+ name: string | null;
1912
+ document: {
1913
+ version: "1.0" | "1.1";
1914
+ metadata: Record<string, unknown>;
1915
+ sections: Record<string, unknown>[];
1916
+ } & {
1917
+ [k: string]: unknown;
1918
+ };
1919
+ created_at: string;
1920
+ updated_at: string;
1921
+ template_id: string | null;
1922
+ subject: string;
1923
+ kind: "broadcast" | "automation" | "notification";
1924
+ preheader: string | null;
1925
+ topic: string;
1926
+ provider_id: string;
1927
+ counts: {
1928
+ sending: number;
1929
+ sent: number;
1930
+ total: number;
1931
+ queued: number;
1932
+ failed: number;
1933
+ skipped: number;
1934
+ };
1935
+ scheduled_at: string | null;
1936
+ ab_test: {
1937
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1938
+ variants: {
1939
+ key: string;
1940
+ subject: string | null;
1941
+ has_document: boolean;
1942
+ }[];
1943
+ test_fraction: number;
1944
+ winner_metric: "opens" | "clicks" | "manual";
1945
+ decide_after_minutes: number | null;
1946
+ decide_at: string | null;
1947
+ winner: string | null;
1948
+ decided_by: "manual" | "metric" | null;
1949
+ decided_at: string | null;
1950
+ } | null;
1951
+ started_at: string | null;
1952
+ finished_at: string | null;
1953
+ pause_reason: string | null;
1954
+ }>;
1955
+ pickAbWinner: (id: string, body: RouteBody<"mailings.pickAbWinner">, opts?: RequestOpts) => Promise<{
1956
+ status: "draft" | "scheduled" | "sending" | "paused" | "sent" | "partially_failed" | "cancelled";
1957
+ id: string;
1958
+ metadata: Record<string, string>;
1959
+ name: string | null;
1960
+ document: {
1961
+ version: "1.0" | "1.1";
1962
+ metadata: Record<string, unknown>;
1963
+ sections: Record<string, unknown>[];
1964
+ } & {
1965
+ [k: string]: unknown;
1966
+ };
1967
+ created_at: string;
1968
+ updated_at: string;
1969
+ template_id: string | null;
1970
+ subject: string;
1971
+ kind: "broadcast" | "automation" | "notification";
1972
+ preheader: string | null;
1973
+ topic: string;
1974
+ provider_id: string;
1975
+ counts: {
1976
+ sending: number;
1977
+ sent: number;
1978
+ total: number;
1979
+ queued: number;
1980
+ failed: number;
1981
+ skipped: number;
1982
+ };
1983
+ scheduled_at: string | null;
1984
+ ab_test: {
1985
+ status: "pending" | "testing" | "awaiting_pick" | "decided";
1986
+ variants: {
1987
+ key: string;
1988
+ subject: string | null;
1989
+ has_document: boolean;
1990
+ }[];
1991
+ test_fraction: number;
1992
+ winner_metric: "opens" | "clicks" | "manual";
1993
+ decide_after_minutes: number | null;
1994
+ decide_at: string | null;
1995
+ winner: string | null;
1996
+ decided_by: "manual" | "metric" | null;
1997
+ decided_at: string | null;
1998
+ } | null;
1999
+ started_at: string | null;
2000
+ finished_at: string | null;
2001
+ pause_reason: string | null;
2002
+ }>;
2003
+ analytics: (id: string, opts?: RequestOpts) => Promise<{
2004
+ variants: {
2005
+ key: string;
2006
+ sent: number;
2007
+ unique_opens: number | null;
2008
+ unique_clicks: number | null;
2009
+ }[] | null;
2010
+ counts: {
2011
+ sending: number;
2012
+ sent: number;
2013
+ total: number;
2014
+ queued: number;
2015
+ failed: number;
2016
+ skipped: number;
2017
+ };
2018
+ mailing_id: string;
2019
+ unique_opens: number | null;
2020
+ unique_clicks: number | null;
2021
+ tracking: {
2022
+ opens: boolean;
2023
+ clicks: boolean;
2024
+ } | null;
2025
+ apple_mpp_opens: number | null;
2026
+ machine_events: number | null;
2027
+ unsubscribes: number;
2028
+ bounces: number;
2029
+ complaints: number;
2030
+ links: {
2031
+ url: string;
2032
+ unique_clicks: number;
2033
+ }[] | null;
2034
+ }>;
2035
+ };
2036
+ messages: {
2037
+ list: (query?: RouteQuery<"messages.list">, opts?: RequestOpts) => Promise<{
2038
+ data: {
2039
+ id: string;
2040
+ error: string | null;
2041
+ created_at: string;
2042
+ subject: string;
2043
+ provider_id: string;
2044
+ to: string;
2045
+ provider_message_id: string | null;
2046
+ mailing_id: string | null;
2047
+ contact_id: string | null;
2048
+ recipient_id: string | null;
2049
+ outcome: "sent" | "failed";
2050
+ is_test: boolean;
2051
+ recipient_count: number;
2052
+ }[];
2053
+ next_cursor: string | null;
2054
+ }>;
2055
+ get: (id: string, opts?: RequestOpts) => Promise<{
2056
+ id: string;
2057
+ error: string | null;
2058
+ created_at: string;
2059
+ html: string;
2060
+ subject: string;
2061
+ provider_id: string;
2062
+ to: string;
2063
+ provider_message_id: string | null;
2064
+ mailing_id: string | null;
2065
+ contact_id: string | null;
2066
+ recipient_id: string | null;
2067
+ outcome: "sent" | "failed";
2068
+ is_test: boolean;
2069
+ recipient_count: number;
2070
+ }>;
2071
+ };
2072
+ webhooks: {
2073
+ list: (query?: RouteQuery<"webhooks.list">, opts?: RequestOpts) => Promise<{
2074
+ data: {
2075
+ id: string;
2076
+ description: string | null;
2077
+ created_at: string;
2078
+ updated_at: string;
2079
+ url: string;
2080
+ events: ("contact.unsubscribed" | "contact.subscribed" | "import.finished" | "mailing.scheduled" | "mailing.schedule_failed" | "mailing.ab_winner_selected" | "message.sent" | "message.failed" | "contact.resubscribed" | "contact.bounced" | "mailing.finished" | "mailing.started" | "contact.tagged" | "contact.updated" | "automation.run_started" | "automation.run_completed" | "automation.run_exited" | "automation.run_failed" | "automation.webhook")[];
2081
+ enabled: boolean;
2082
+ }[];
2083
+ next_cursor: string | null;
2084
+ }>;
2085
+ create: (body: RouteBody<"webhooks.create">, opts?: RequestOpts) => Promise<{
2086
+ endpoint: {
2087
+ id: string;
2088
+ description: string | null;
2089
+ created_at: string;
2090
+ updated_at: string;
2091
+ url: string;
2092
+ events: ("contact.unsubscribed" | "contact.subscribed" | "import.finished" | "mailing.scheduled" | "mailing.schedule_failed" | "mailing.ab_winner_selected" | "message.sent" | "message.failed" | "contact.resubscribed" | "contact.bounced" | "mailing.finished" | "mailing.started" | "contact.tagged" | "contact.updated" | "automation.run_started" | "automation.run_completed" | "automation.run_exited" | "automation.run_failed" | "automation.webhook")[];
2093
+ enabled: boolean;
2094
+ };
2095
+ secret: string;
2096
+ }>;
2097
+ get: (id: string, opts?: RequestOpts) => Promise<{
2098
+ id: string;
2099
+ description: string | null;
2100
+ created_at: string;
2101
+ updated_at: string;
2102
+ url: string;
2103
+ events: ("contact.unsubscribed" | "contact.subscribed" | "import.finished" | "mailing.scheduled" | "mailing.schedule_failed" | "mailing.ab_winner_selected" | "message.sent" | "message.failed" | "contact.resubscribed" | "contact.bounced" | "mailing.finished" | "mailing.started" | "contact.tagged" | "contact.updated" | "automation.run_started" | "automation.run_completed" | "automation.run_exited" | "automation.run_failed" | "automation.webhook")[];
2104
+ enabled: boolean;
2105
+ }>;
2106
+ update: (id: string, body: RouteBody<"webhooks.update">, opts?: RequestOpts) => Promise<{
2107
+ id: string;
2108
+ description: string | null;
2109
+ created_at: string;
2110
+ updated_at: string;
2111
+ url: string;
2112
+ events: ("contact.unsubscribed" | "contact.subscribed" | "import.finished" | "mailing.scheduled" | "mailing.schedule_failed" | "mailing.ab_winner_selected" | "message.sent" | "message.failed" | "contact.resubscribed" | "contact.bounced" | "mailing.finished" | "mailing.started" | "contact.tagged" | "contact.updated" | "automation.run_started" | "automation.run_completed" | "automation.run_exited" | "automation.run_failed" | "automation.webhook")[];
2113
+ enabled: boolean;
2114
+ }>;
2115
+ delete: (id: string, opts?: RequestOpts) => Promise<{
2116
+ ok: true;
2117
+ }>;
2118
+ rotateSecret: (id: string, opts?: RequestOpts) => Promise<{
2119
+ endpoint: {
2120
+ id: string;
2121
+ description: string | null;
2122
+ created_at: string;
2123
+ updated_at: string;
2124
+ url: string;
2125
+ events: ("contact.unsubscribed" | "contact.subscribed" | "import.finished" | "mailing.scheduled" | "mailing.schedule_failed" | "mailing.ab_winner_selected" | "message.sent" | "message.failed" | "contact.resubscribed" | "contact.bounced" | "mailing.finished" | "mailing.started" | "contact.tagged" | "contact.updated" | "automation.run_started" | "automation.run_completed" | "automation.run_exited" | "automation.run_failed" | "automation.webhook")[];
2126
+ enabled: boolean;
2127
+ };
2128
+ secret: string;
2129
+ }>;
2130
+ deliveries: (id: string, query?: RouteQuery<"webhooks.deliveries">, opts?: RequestOpts) => Promise<{
2131
+ data: {
2132
+ status: "pending" | "failed" | "succeeded";
2133
+ id: string;
2134
+ created_at: string;
2135
+ attempts: number;
2136
+ last_error: string | null;
2137
+ endpoint_id: string;
2138
+ event_id: string;
2139
+ event_type: "contact.unsubscribed" | "contact.subscribed" | "import.finished" | "mailing.scheduled" | "mailing.schedule_failed" | "mailing.ab_winner_selected" | "message.sent" | "message.failed" | "contact.resubscribed" | "contact.bounced" | "mailing.finished" | "mailing.started" | "contact.tagged" | "contact.updated" | "automation.run_started" | "automation.run_completed" | "automation.run_exited" | "automation.run_failed" | "automation.webhook";
2140
+ last_status_code: number | null;
2141
+ next_attempt_at: string | null;
2142
+ delivered_at: string | null;
2143
+ }[];
2144
+ next_cursor: string | null;
2145
+ }>;
2146
+ redeliver: (id: string, deliveryId: string, opts?: RequestOpts) => Promise<{
2147
+ status: "pending" | "failed" | "succeeded";
2148
+ id: string;
2149
+ created_at: string;
2150
+ attempts: number;
2151
+ last_error: string | null;
2152
+ endpoint_id: string;
2153
+ event_id: string;
2154
+ event_type: "contact.unsubscribed" | "contact.subscribed" | "import.finished" | "mailing.scheduled" | "mailing.schedule_failed" | "mailing.ab_winner_selected" | "message.sent" | "message.failed" | "contact.resubscribed" | "contact.bounced" | "mailing.finished" | "mailing.started" | "contact.tagged" | "contact.updated" | "automation.run_started" | "automation.run_completed" | "automation.run_exited" | "automation.run_failed" | "automation.webhook";
2155
+ last_status_code: number | null;
2156
+ next_attempt_at: string | null;
2157
+ delivered_at: string | null;
2158
+ }>;
2159
+ };
2160
+ tags: {
2161
+ list: (query?: RouteQuery<"tags.list">, opts?: RequestOpts) => Promise<{
2162
+ data: {
2163
+ id: string;
2164
+ name: string;
2165
+ created_at: string;
2166
+ slug: string;
2167
+ contact_count: number;
2168
+ }[];
2169
+ next_cursor: string | null;
2170
+ }>;
2171
+ create: (body: RouteBody<"tags.create">, opts?: RequestOpts) => Promise<{
2172
+ id: string;
2173
+ name: string;
2174
+ created_at: string;
2175
+ slug: string;
2176
+ contact_count: number;
2177
+ }>;
2178
+ delete: (id: string, opts?: RequestOpts) => Promise<{
2179
+ ok: true;
2180
+ }>;
2181
+ assign: (id: string, body: RouteBody<"tags.assign">, opts?: RequestOpts) => Promise<{
2182
+ id: string;
2183
+ name: string;
2184
+ created_at: string;
2185
+ slug: string;
2186
+ contact_count: number;
2187
+ }>;
2188
+ unassign: (id: string, body: RouteBody<"tags.unassign">, opts?: RequestOpts) => Promise<{
2189
+ id: string;
2190
+ name: string;
2191
+ created_at: string;
2192
+ slug: string;
2193
+ contact_count: number;
2194
+ }>;
2195
+ };
2196
+ segments: {
2197
+ list: (query?: RouteQuery<"segments.list">, opts?: RequestOpts) => Promise<{
2198
+ data: {
2199
+ filter: _marlinjai_mail_contract.SegmentFilter;
2200
+ id: string;
2201
+ name: string;
2202
+ created_at: string;
2203
+ updated_at: string;
2204
+ contact_count: number;
2205
+ }[];
2206
+ next_cursor: string | null;
2207
+ }>;
2208
+ create: (body: RouteBody<"segments.create">, opts?: RequestOpts) => Promise<{
2209
+ filter: _marlinjai_mail_contract.SegmentFilter;
2210
+ id: string;
2211
+ name: string;
2212
+ created_at: string;
2213
+ updated_at: string;
2214
+ contact_count: number;
2215
+ }>;
2216
+ /** Counts what a filter matches, without saving it. */
2217
+ preview: (body: RouteBody<"segments.preview">, opts?: RequestOpts) => Promise<{
2218
+ contact_count: number;
2219
+ sample: {
2220
+ id: string;
2221
+ email: string;
2222
+ }[];
2223
+ }>;
2224
+ get: (id: string, opts?: RequestOpts) => Promise<{
2225
+ filter: _marlinjai_mail_contract.SegmentFilter;
2226
+ id: string;
2227
+ name: string;
2228
+ created_at: string;
2229
+ updated_at: string;
2230
+ contact_count: number;
2231
+ }>;
2232
+ update: (id: string, body: RouteBody<"segments.update">, opts?: RequestOpts) => Promise<{
2233
+ filter: _marlinjai_mail_contract.SegmentFilter;
2234
+ id: string;
2235
+ name: string;
2236
+ created_at: string;
2237
+ updated_at: string;
2238
+ contact_count: number;
2239
+ }>;
2240
+ delete: (id: string, opts?: RequestOpts) => Promise<{
2241
+ ok: true;
2242
+ }>;
2243
+ };
2244
+ signupForms: {
2245
+ list: (query?: RouteQuery<"signupForms.list">, opts?: RequestOpts) => Promise<{
2246
+ data: {
2247
+ id: string;
2248
+ version: number;
2249
+ name: string;
2250
+ created_at: string;
2251
+ updated_at: string;
2252
+ provider_id: string;
2253
+ title: string;
2254
+ consent_text: string;
2255
+ translations: Record<string, {
2256
+ title: string;
2257
+ consent_text: string;
2258
+ }>;
2259
+ topics: string[];
2260
+ tags: string[];
2261
+ fields: ("first_name" | "last_name")[];
2262
+ double_opt_in: true;
2263
+ confirmation_template_id: string | null;
2264
+ redirect_url: string | null;
2265
+ allowed_origins: string[];
2266
+ }[];
2267
+ next_cursor: string | null;
2268
+ }>;
2269
+ create: (body: RouteBody<"signupForms.create">, opts?: RequestOpts) => Promise<{
2270
+ id: string;
2271
+ version: number;
2272
+ name: string;
2273
+ created_at: string;
2274
+ updated_at: string;
2275
+ provider_id: string;
2276
+ title: string;
2277
+ consent_text: string;
2278
+ translations: Record<string, {
2279
+ title: string;
2280
+ consent_text: string;
2281
+ }>;
2282
+ topics: string[];
2283
+ tags: string[];
2284
+ fields: ("first_name" | "last_name")[];
2285
+ double_opt_in: true;
2286
+ confirmation_template_id: string | null;
2287
+ redirect_url: string | null;
2288
+ allowed_origins: string[];
2289
+ }>;
2290
+ get: (id: string, opts?: RequestOpts) => Promise<{
2291
+ id: string;
2292
+ version: number;
2293
+ name: string;
2294
+ created_at: string;
2295
+ updated_at: string;
2296
+ provider_id: string;
2297
+ title: string;
2298
+ consent_text: string;
2299
+ translations: Record<string, {
2300
+ title: string;
2301
+ consent_text: string;
2302
+ }>;
2303
+ topics: string[];
2304
+ tags: string[];
2305
+ fields: ("first_name" | "last_name")[];
2306
+ double_opt_in: true;
2307
+ confirmation_template_id: string | null;
2308
+ redirect_url: string | null;
2309
+ allowed_origins: string[];
2310
+ }>;
2311
+ embed: (id: string, opts?: RequestOpts) => Promise<{
2312
+ html: string;
2313
+ hosted_url: string;
2314
+ script_url: string;
2315
+ token_url: string;
2316
+ }>;
2317
+ update: (id: string, body: RouteBody<"signupForms.update">, opts?: RequestOpts) => Promise<{
2318
+ id: string;
2319
+ version: number;
2320
+ name: string;
2321
+ created_at: string;
2322
+ updated_at: string;
2323
+ provider_id: string;
2324
+ title: string;
2325
+ consent_text: string;
2326
+ translations: Record<string, {
2327
+ title: string;
2328
+ consent_text: string;
2329
+ }>;
2330
+ topics: string[];
2331
+ tags: string[];
2332
+ fields: ("first_name" | "last_name")[];
2333
+ double_opt_in: true;
2334
+ confirmation_template_id: string | null;
2335
+ redirect_url: string | null;
2336
+ allowed_origins: string[];
2337
+ }>;
2338
+ delete: (id: string, opts?: RequestOpts) => Promise<{
2339
+ ok: true;
2340
+ }>;
2341
+ /** The public submission route: usable without a workspace key in a browser form handler. */
2342
+ submit: (id: string, body: RouteBody<"signupForms.submit">, opts?: RequestOpts) => Promise<{
2343
+ ok: true;
2344
+ }>;
2345
+ };
2346
+ imports: {
2347
+ /** Step 1: upload the CSV. The answer carries its columns, a sample and a suggested mapping. */
2348
+ create: (file: Blob, filename?: string, opts?: RequestOpts) => Promise<{
2349
+ status: "cancelled" | "failed" | "uploaded" | "validating" | "validated" | "committing" | "completed";
2350
+ id: string;
2351
+ error: string | null;
2352
+ created_at: string;
2353
+ updated_at: string;
2354
+ finished_at: string | null;
2355
+ sample: string[][];
2356
+ topics: string[];
2357
+ tags: string[];
2358
+ mapping: Record<string, string> | null;
2359
+ update_existing: boolean;
2360
+ mapping_version: number;
2361
+ file_name: string | null;
2362
+ file_bytes: number;
2363
+ total_rows: number;
2364
+ columns: string[];
2365
+ suggested_mapping: Record<string, string>;
2366
+ dry_run: {
2367
+ skipped: number;
2368
+ suppressed: number;
2369
+ created: number;
2370
+ updated: number;
2371
+ unchanged: number;
2372
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2373
+ topics_withheld: number;
2374
+ } | null;
2375
+ result: {
2376
+ skipped: number;
2377
+ suppressed: number;
2378
+ created: number;
2379
+ updated: number;
2380
+ unchanged: number;
2381
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2382
+ topics_withheld: number;
2383
+ } | null;
2384
+ processed_rows: number;
2385
+ }>;
2386
+ list: (query?: RouteQuery<"imports.list">, opts?: RequestOpts) => Promise<{
2387
+ data: {
2388
+ status: "cancelled" | "failed" | "uploaded" | "validating" | "validated" | "committing" | "completed";
2389
+ id: string;
2390
+ error: string | null;
2391
+ created_at: string;
2392
+ updated_at: string;
2393
+ finished_at: string | null;
2394
+ sample: string[][];
2395
+ topics: string[];
2396
+ tags: string[];
2397
+ mapping: Record<string, string> | null;
2398
+ update_existing: boolean;
2399
+ mapping_version: number;
2400
+ file_name: string | null;
2401
+ file_bytes: number;
2402
+ total_rows: number;
2403
+ columns: string[];
2404
+ suggested_mapping: Record<string, string>;
2405
+ dry_run: {
2406
+ skipped: number;
2407
+ suppressed: number;
2408
+ created: number;
2409
+ updated: number;
2410
+ unchanged: number;
2411
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2412
+ topics_withheld: number;
2413
+ } | null;
2414
+ result: {
2415
+ skipped: number;
2416
+ suppressed: number;
2417
+ created: number;
2418
+ updated: number;
2419
+ unchanged: number;
2420
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2421
+ topics_withheld: number;
2422
+ } | null;
2423
+ processed_rows: number;
2424
+ }[];
2425
+ next_cursor: string | null;
2426
+ }>;
2427
+ get: (id: string, opts?: RequestOpts) => Promise<{
2428
+ status: "cancelled" | "failed" | "uploaded" | "validating" | "validated" | "committing" | "completed";
2429
+ id: string;
2430
+ error: string | null;
2431
+ created_at: string;
2432
+ updated_at: string;
2433
+ finished_at: string | null;
2434
+ sample: string[][];
2435
+ topics: string[];
2436
+ tags: string[];
2437
+ mapping: Record<string, string> | null;
2438
+ update_existing: boolean;
2439
+ mapping_version: number;
2440
+ file_name: string | null;
2441
+ file_bytes: number;
2442
+ total_rows: number;
2443
+ columns: string[];
2444
+ suggested_mapping: Record<string, string>;
2445
+ dry_run: {
2446
+ skipped: number;
2447
+ suppressed: number;
2448
+ created: number;
2449
+ updated: number;
2450
+ unchanged: number;
2451
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2452
+ topics_withheld: number;
2453
+ } | null;
2454
+ result: {
2455
+ skipped: number;
2456
+ suppressed: number;
2457
+ created: number;
2458
+ updated: number;
2459
+ unchanged: number;
2460
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2461
+ topics_withheld: number;
2462
+ } | null;
2463
+ processed_rows: number;
2464
+ }>;
2465
+ /** Step 2: set (or revise) the mapping; the dry run starts, and any earlier one is discarded. */
2466
+ setMapping: (id: string, body: RouteBody<"imports.setMapping">, opts?: RequestOpts) => Promise<{
2467
+ status: "cancelled" | "failed" | "uploaded" | "validating" | "validated" | "committing" | "completed";
2468
+ id: string;
2469
+ error: string | null;
2470
+ created_at: string;
2471
+ updated_at: string;
2472
+ finished_at: string | null;
2473
+ sample: string[][];
2474
+ topics: string[];
2475
+ tags: string[];
2476
+ mapping: Record<string, string> | null;
2477
+ update_existing: boolean;
2478
+ mapping_version: number;
2479
+ file_name: string | null;
2480
+ file_bytes: number;
2481
+ total_rows: number;
2482
+ columns: string[];
2483
+ suggested_mapping: Record<string, string>;
2484
+ dry_run: {
2485
+ skipped: number;
2486
+ suppressed: number;
2487
+ created: number;
2488
+ updated: number;
2489
+ unchanged: number;
2490
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2491
+ topics_withheld: number;
2492
+ } | null;
2493
+ result: {
2494
+ skipped: number;
2495
+ suppressed: number;
2496
+ created: number;
2497
+ updated: number;
2498
+ unchanged: number;
2499
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2500
+ topics_withheld: number;
2501
+ } | null;
2502
+ processed_rows: number;
2503
+ }>;
2504
+ /** Step 3: commit the dry run of `mapping_version`. */
2505
+ commit: (id: string, body: RouteBody<"imports.commit">, opts?: RequestOpts) => Promise<{
2506
+ status: "cancelled" | "failed" | "uploaded" | "validating" | "validated" | "committing" | "completed";
2507
+ id: string;
2508
+ error: string | null;
2509
+ created_at: string;
2510
+ updated_at: string;
2511
+ finished_at: string | null;
2512
+ sample: string[][];
2513
+ topics: string[];
2514
+ tags: string[];
2515
+ mapping: Record<string, string> | null;
2516
+ update_existing: boolean;
2517
+ mapping_version: number;
2518
+ file_name: string | null;
2519
+ file_bytes: number;
2520
+ total_rows: number;
2521
+ columns: string[];
2522
+ suggested_mapping: Record<string, string>;
2523
+ dry_run: {
2524
+ skipped: number;
2525
+ suppressed: number;
2526
+ created: number;
2527
+ updated: number;
2528
+ unchanged: number;
2529
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2530
+ topics_withheld: number;
2531
+ } | null;
2532
+ result: {
2533
+ skipped: number;
2534
+ suppressed: number;
2535
+ created: number;
2536
+ updated: number;
2537
+ unchanged: number;
2538
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2539
+ topics_withheld: number;
2540
+ } | null;
2541
+ processed_rows: number;
2542
+ }>;
2543
+ cancel: (id: string, opts?: RequestOpts) => Promise<{
2544
+ status: "cancelled" | "failed" | "uploaded" | "validating" | "validated" | "committing" | "completed";
2545
+ id: string;
2546
+ error: string | null;
2547
+ created_at: string;
2548
+ updated_at: string;
2549
+ finished_at: string | null;
2550
+ sample: string[][];
2551
+ topics: string[];
2552
+ tags: string[];
2553
+ mapping: Record<string, string> | null;
2554
+ update_existing: boolean;
2555
+ mapping_version: number;
2556
+ file_name: string | null;
2557
+ file_bytes: number;
2558
+ total_rows: number;
2559
+ columns: string[];
2560
+ suggested_mapping: Record<string, string>;
2561
+ dry_run: {
2562
+ skipped: number;
2563
+ suppressed: number;
2564
+ created: number;
2565
+ updated: number;
2566
+ unchanged: number;
2567
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2568
+ topics_withheld: number;
2569
+ } | null;
2570
+ result: {
2571
+ skipped: number;
2572
+ suppressed: number;
2573
+ created: number;
2574
+ updated: number;
2575
+ unchanged: number;
2576
+ skipped_by_reason: Partial<Record<"missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count", number>>;
2577
+ topics_withheld: number;
2578
+ } | null;
2579
+ processed_rows: number;
2580
+ }>;
2581
+ rows: (id: string, query?: RouteQuery<"imports.rows">, opts?: RequestOpts) => Promise<{
2582
+ data: {
2583
+ message: string | null;
2584
+ reason: "missing_email" | "invalid_email" | "duplicate_in_file" | "invalid_value" | "external_id_conflict" | "wrong_column_count" | null;
2585
+ contact_id: string | null;
2586
+ email: string | null;
2587
+ outcome: "skipped" | "suppressed" | "created" | "updated" | "unchanged";
2588
+ row: number;
2589
+ }[];
2590
+ next_cursor: string | null;
2591
+ }>;
2592
+ };
2593
+ tracking: {
2594
+ get: (opts?: RequestOpts) => Promise<{
2595
+ opens: boolean;
2596
+ clicks: boolean;
2597
+ }>;
2598
+ update: (body: RouteBody<"tracking.update">, opts?: RequestOpts) => Promise<{
2599
+ opens: boolean;
2600
+ clicks: boolean;
2601
+ }>;
2602
+ };
2603
+ contactProperties: {
2604
+ list: (opts?: RequestOpts) => Promise<{
2605
+ data: {
2606
+ type: "string" | "number" | "boolean" | "date";
2607
+ key: string;
2608
+ label: string;
2609
+ }[];
2610
+ }>;
2611
+ create: (body: RouteBody<"contactProperties.create">, opts?: RequestOpts) => Promise<{
2612
+ type: "string" | "number" | "boolean" | "date";
2613
+ key: string;
2614
+ label: string;
2615
+ }>;
2616
+ delete: (key: string, opts?: RequestOpts) => Promise<{
2617
+ ok: true;
2618
+ }>;
2619
+ };
2620
+ billing: {
2621
+ plans: (opts?: RequestOpts) => Promise<{
2622
+ data: {
2623
+ id: "free" | "starter" | "growth" | "design_partner";
2624
+ name: string;
2625
+ monthly_price_cents: number | null;
2626
+ currency: string;
2627
+ limits: {
2628
+ monthly_messages: number | null;
2629
+ contacts: number | null;
2630
+ members: number | null;
2631
+ providers: number | null;
2632
+ webhook_endpoints: number | null;
2633
+ active_automations: number | null;
2634
+ automation_steps: number | null;
2635
+ };
2636
+ features: {
2637
+ tracking: boolean;
2638
+ ab_testing: boolean;
2639
+ custom_domains: boolean;
2640
+ automations: boolean;
2641
+ };
2642
+ sellable: boolean;
2643
+ }[];
2644
+ }>;
2645
+ subscription: (opts?: RequestOpts) => Promise<{
2646
+ status: "cancelled" | "active" | "trialing" | "past_due";
2647
+ workspace_id: string;
2648
+ plan: "free" | "starter" | "growth" | "design_partner";
2649
+ current_period_start: string;
2650
+ current_period_end: string;
2651
+ cancel_at_period_end: boolean;
2652
+ billing_exempt: boolean;
2653
+ }>;
2654
+ usage: (opts?: RequestOpts) => Promise<{
2655
+ warnings: {
2656
+ limit: number;
2657
+ metric: "contacts" | "members" | "providers" | "webhook_endpoints" | "active_automations" | "messages";
2658
+ used: number;
2659
+ level: "reached" | "approaching";
2660
+ }[];
2661
+ plan: "free" | "starter" | "growth" | "design_partner";
2662
+ period_start: string;
2663
+ period_end: string;
2664
+ metrics: Partial<Record<"contacts" | "members" | "providers" | "webhook_endpoints" | "active_automations" | "messages", {
2665
+ limit: number | null;
2666
+ used: number;
2667
+ }>>;
2668
+ }>;
2669
+ checkout: (body: RouteBody<"billing.checkout">, opts?: RequestOpts) => Promise<{
2670
+ url: string;
2671
+ }>;
2672
+ portal: (body: RouteBody<"billing.portal">, opts?: RequestOpts) => Promise<{
2673
+ url: string;
2674
+ }>;
2675
+ };
2676
+ automations: {
2677
+ list: (query?: RouteQuery<"automations.list">, opts?: RequestOpts) => Promise<{
2678
+ data: {
2679
+ status: "archived" | "draft" | "paused" | "active";
2680
+ id: string;
2681
+ name: string;
2682
+ created_at: string;
2683
+ updated_at: string;
2684
+ topic: string;
2685
+ provider_id: string | null;
2686
+ counts: {
2687
+ failed: number;
2688
+ completed: number;
2689
+ started: number;
2690
+ in_progress: number;
2691
+ exited: number;
2692
+ };
2693
+ settings: {
2694
+ re_entry: "off" | "after_exit";
2695
+ re_entry_cooldown_s?: number | null | undefined;
2696
+ quiet_hours?: {
2697
+ start: string;
2698
+ end: string;
2699
+ weekdays?: number[] | null | undefined;
2700
+ } | null | undefined;
2701
+ exit_filter?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2702
+ };
2703
+ published_version: number | null;
2704
+ draft_version: number;
2705
+ published_at: string | null;
2706
+ }[];
2707
+ next_cursor: string | null;
2708
+ }>;
2709
+ create: (body: RouteBody<"automations.create">, opts?: RequestOpts) => Promise<{
2710
+ status: "archived" | "draft" | "paused" | "active";
2711
+ id: string;
2712
+ name: string;
2713
+ created_at: string;
2714
+ updated_at: string;
2715
+ topic: string;
2716
+ provider_id: string | null;
2717
+ counts: {
2718
+ failed: number;
2719
+ completed: number;
2720
+ started: number;
2721
+ in_progress: number;
2722
+ exited: number;
2723
+ };
2724
+ settings: {
2725
+ re_entry: "off" | "after_exit";
2726
+ re_entry_cooldown_s?: number | null | undefined;
2727
+ quiet_hours?: {
2728
+ start: string;
2729
+ end: string;
2730
+ weekdays?: number[] | null | undefined;
2731
+ } | null | undefined;
2732
+ exit_filter?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2733
+ };
2734
+ published_version: number | null;
2735
+ draft_version: number;
2736
+ published_at: string | null;
2737
+ flow: {
2738
+ triggers: ({
2739
+ kind: "topic_subscribed";
2740
+ topic: string;
2741
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2742
+ } | {
2743
+ kind: "form_confirmed";
2744
+ form_id: string;
2745
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2746
+ } | {
2747
+ kind: "tag_added";
2748
+ tag: string;
2749
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2750
+ } | {
2751
+ key: string;
2752
+ kind: "property_changed";
2753
+ to?: _marlinjai_mail_contract.JsonValue | undefined;
2754
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2755
+ } | {
2756
+ name: string;
2757
+ kind: "event";
2758
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2759
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2760
+ } | {
2761
+ kind: "manual";
2762
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2763
+ } | {
2764
+ at: string;
2765
+ key: string;
2766
+ kind: "date_anniversary";
2767
+ offset_days: number;
2768
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2769
+ } | {
2770
+ at: string;
2771
+ kind: "exact_date";
2772
+ on: string;
2773
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2774
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2775
+ } | {
2776
+ kind: "segment_entered";
2777
+ segment_id: string;
2778
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2779
+ } | {
2780
+ kind: "link_clicked";
2781
+ mailing_id: string;
2782
+ url?: string | undefined;
2783
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2784
+ })[];
2785
+ entry: string | null;
2786
+ steps: Record<string, {
2787
+ subject: string;
2788
+ kind: "email";
2789
+ next: string | null;
2790
+ document?: zod.objectOutputType<{
2791
+ version: zod.ZodEnum<["1.0", "1.1"]>;
2792
+ metadata: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
2793
+ sections: zod.ZodArray<zod.ZodRecord<zod.ZodString, zod.ZodUnknown>, "many">;
2794
+ }, zod.ZodTypeAny, "passthrough"> | null | undefined;
2795
+ template_id?: string | null | undefined;
2796
+ preheader?: string | null | undefined;
2797
+ label?: string | null | undefined;
2798
+ } | {
2799
+ kind: "delay";
2800
+ next: string | null;
2801
+ wait: {
2802
+ mode: "duration";
2803
+ seconds: number;
2804
+ } | {
2805
+ at: string;
2806
+ mode: "time_of_day";
2807
+ } | {
2808
+ at: string;
2809
+ mode: "weekday";
2810
+ weekday: number;
2811
+ } | {
2812
+ at: string;
2813
+ on: string;
2814
+ mode: "date";
2815
+ passed: "skip" | "stop";
2816
+ } | {
2817
+ at: string;
2818
+ key: string;
2819
+ offset_days: number;
2820
+ mode: "date_property";
2821
+ passed: "skip" | "stop" | "continue";
2822
+ };
2823
+ label?: string | null | undefined;
2824
+ } | {
2825
+ filter: _marlinjai_mail_contract.SegmentFilter;
2826
+ kind: "condition";
2827
+ yes: string | null;
2828
+ no: string | null;
2829
+ label?: string | null | undefined;
2830
+ wait_for?: {
2831
+ up_to_s: number;
2832
+ on_timeout: "yes" | "no";
2833
+ } | null | undefined;
2834
+ } | {
2835
+ kind: "split";
2836
+ branches: {
2837
+ key: string;
2838
+ next: string | null;
2839
+ weight: number;
2840
+ }[];
2841
+ label?: string | null | undefined;
2842
+ } | {
2843
+ kind: "goto";
2844
+ target: string | null;
2845
+ label?: string | null | undefined;
2846
+ } | {
2847
+ kind: "webhook";
2848
+ next: string | null;
2849
+ endpoint_id: string | null;
2850
+ label?: string | null | undefined;
2851
+ payload?: _marlinjai_mail_contract.JsonValue | undefined;
2852
+ } | {
2853
+ subject: string;
2854
+ kind: "notify";
2855
+ to: "owner" | "admins" | {
2856
+ member_id: string;
2857
+ };
2858
+ next: string | null;
2859
+ body: string;
2860
+ label?: string | null | undefined;
2861
+ } | {
2862
+ kind: "add_tag";
2863
+ tag: string;
2864
+ next: string | null;
2865
+ label?: string | null | undefined;
2866
+ } | {
2867
+ kind: "remove_tag";
2868
+ tag: string;
2869
+ next: string | null;
2870
+ label?: string | null | undefined;
2871
+ } | {
2872
+ value: _marlinjai_mail_contract.JsonValue;
2873
+ key: string;
2874
+ kind: "set_property";
2875
+ next: string | null;
2876
+ label?: string | null | undefined;
2877
+ } | {
2878
+ kind: "subscribe_topic";
2879
+ topic: string;
2880
+ next: string | null;
2881
+ label?: string | null | undefined;
2882
+ } | {
2883
+ kind: "unsubscribe";
2884
+ next: string | null;
2885
+ scope: "topic" | "all";
2886
+ label?: string | null | undefined;
2887
+ } | {
2888
+ kind: "exit";
2889
+ label?: string | null | undefined;
2890
+ }>;
2891
+ };
2892
+ published_flow: {
2893
+ triggers: ({
2894
+ kind: "topic_subscribed";
2895
+ topic: string;
2896
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2897
+ } | {
2898
+ kind: "form_confirmed";
2899
+ form_id: string;
2900
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2901
+ } | {
2902
+ kind: "tag_added";
2903
+ tag: string;
2904
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2905
+ } | {
2906
+ key: string;
2907
+ kind: "property_changed";
2908
+ to?: _marlinjai_mail_contract.JsonValue | undefined;
2909
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2910
+ } | {
2911
+ name: string;
2912
+ kind: "event";
2913
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2914
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2915
+ } | {
2916
+ kind: "manual";
2917
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2918
+ } | {
2919
+ at: string;
2920
+ key: string;
2921
+ kind: "date_anniversary";
2922
+ offset_days: number;
2923
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2924
+ } | {
2925
+ at: string;
2926
+ kind: "exact_date";
2927
+ on: string;
2928
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2929
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2930
+ } | {
2931
+ kind: "segment_entered";
2932
+ segment_id: string;
2933
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2934
+ } | {
2935
+ kind: "link_clicked";
2936
+ mailing_id: string;
2937
+ url?: string | undefined;
2938
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
2939
+ })[];
2940
+ entry: string | null;
2941
+ steps: Record<string, {
2942
+ subject: string;
2943
+ kind: "email";
2944
+ next: string | null;
2945
+ document?: zod.objectOutputType<{
2946
+ version: zod.ZodEnum<["1.0", "1.1"]>;
2947
+ metadata: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
2948
+ sections: zod.ZodArray<zod.ZodRecord<zod.ZodString, zod.ZodUnknown>, "many">;
2949
+ }, zod.ZodTypeAny, "passthrough"> | null | undefined;
2950
+ template_id?: string | null | undefined;
2951
+ preheader?: string | null | undefined;
2952
+ label?: string | null | undefined;
2953
+ } | {
2954
+ kind: "delay";
2955
+ next: string | null;
2956
+ wait: {
2957
+ mode: "duration";
2958
+ seconds: number;
2959
+ } | {
2960
+ at: string;
2961
+ mode: "time_of_day";
2962
+ } | {
2963
+ at: string;
2964
+ mode: "weekday";
2965
+ weekday: number;
2966
+ } | {
2967
+ at: string;
2968
+ on: string;
2969
+ mode: "date";
2970
+ passed: "skip" | "stop";
2971
+ } | {
2972
+ at: string;
2973
+ key: string;
2974
+ offset_days: number;
2975
+ mode: "date_property";
2976
+ passed: "skip" | "stop" | "continue";
2977
+ };
2978
+ label?: string | null | undefined;
2979
+ } | {
2980
+ filter: _marlinjai_mail_contract.SegmentFilter;
2981
+ kind: "condition";
2982
+ yes: string | null;
2983
+ no: string | null;
2984
+ label?: string | null | undefined;
2985
+ wait_for?: {
2986
+ up_to_s: number;
2987
+ on_timeout: "yes" | "no";
2988
+ } | null | undefined;
2989
+ } | {
2990
+ kind: "split";
2991
+ branches: {
2992
+ key: string;
2993
+ next: string | null;
2994
+ weight: number;
2995
+ }[];
2996
+ label?: string | null | undefined;
2997
+ } | {
2998
+ kind: "goto";
2999
+ target: string | null;
3000
+ label?: string | null | undefined;
3001
+ } | {
3002
+ kind: "webhook";
3003
+ next: string | null;
3004
+ endpoint_id: string | null;
3005
+ label?: string | null | undefined;
3006
+ payload?: _marlinjai_mail_contract.JsonValue | undefined;
3007
+ } | {
3008
+ subject: string;
3009
+ kind: "notify";
3010
+ to: "owner" | "admins" | {
3011
+ member_id: string;
3012
+ };
3013
+ next: string | null;
3014
+ body: string;
3015
+ label?: string | null | undefined;
3016
+ } | {
3017
+ kind: "add_tag";
3018
+ tag: string;
3019
+ next: string | null;
3020
+ label?: string | null | undefined;
3021
+ } | {
3022
+ kind: "remove_tag";
3023
+ tag: string;
3024
+ next: string | null;
3025
+ label?: string | null | undefined;
3026
+ } | {
3027
+ value: _marlinjai_mail_contract.JsonValue;
3028
+ key: string;
3029
+ kind: "set_property";
3030
+ next: string | null;
3031
+ label?: string | null | undefined;
3032
+ } | {
3033
+ kind: "subscribe_topic";
3034
+ topic: string;
3035
+ next: string | null;
3036
+ label?: string | null | undefined;
3037
+ } | {
3038
+ kind: "unsubscribe";
3039
+ next: string | null;
3040
+ scope: "topic" | "all";
3041
+ label?: string | null | undefined;
3042
+ } | {
3043
+ kind: "exit";
3044
+ label?: string | null | undefined;
3045
+ }>;
3046
+ } | null;
3047
+ }>;
3048
+ get: (id: string, opts?: RequestOpts) => Promise<{
3049
+ status: "archived" | "draft" | "paused" | "active";
3050
+ id: string;
3051
+ name: string;
3052
+ created_at: string;
3053
+ updated_at: string;
3054
+ topic: string;
3055
+ provider_id: string | null;
3056
+ counts: {
3057
+ failed: number;
3058
+ completed: number;
3059
+ started: number;
3060
+ in_progress: number;
3061
+ exited: number;
3062
+ };
3063
+ settings: {
3064
+ re_entry: "off" | "after_exit";
3065
+ re_entry_cooldown_s?: number | null | undefined;
3066
+ quiet_hours?: {
3067
+ start: string;
3068
+ end: string;
3069
+ weekdays?: number[] | null | undefined;
3070
+ } | null | undefined;
3071
+ exit_filter?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3072
+ };
3073
+ published_version: number | null;
3074
+ draft_version: number;
3075
+ published_at: string | null;
3076
+ flow: {
3077
+ triggers: ({
3078
+ kind: "topic_subscribed";
3079
+ topic: string;
3080
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3081
+ } | {
3082
+ kind: "form_confirmed";
3083
+ form_id: string;
3084
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3085
+ } | {
3086
+ kind: "tag_added";
3087
+ tag: string;
3088
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3089
+ } | {
3090
+ key: string;
3091
+ kind: "property_changed";
3092
+ to?: _marlinjai_mail_contract.JsonValue | undefined;
3093
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3094
+ } | {
3095
+ name: string;
3096
+ kind: "event";
3097
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3098
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3099
+ } | {
3100
+ kind: "manual";
3101
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3102
+ } | {
3103
+ at: string;
3104
+ key: string;
3105
+ kind: "date_anniversary";
3106
+ offset_days: number;
3107
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3108
+ } | {
3109
+ at: string;
3110
+ kind: "exact_date";
3111
+ on: string;
3112
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3113
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3114
+ } | {
3115
+ kind: "segment_entered";
3116
+ segment_id: string;
3117
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3118
+ } | {
3119
+ kind: "link_clicked";
3120
+ mailing_id: string;
3121
+ url?: string | undefined;
3122
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3123
+ })[];
3124
+ entry: string | null;
3125
+ steps: Record<string, {
3126
+ subject: string;
3127
+ kind: "email";
3128
+ next: string | null;
3129
+ document?: zod.objectOutputType<{
3130
+ version: zod.ZodEnum<["1.0", "1.1"]>;
3131
+ metadata: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
3132
+ sections: zod.ZodArray<zod.ZodRecord<zod.ZodString, zod.ZodUnknown>, "many">;
3133
+ }, zod.ZodTypeAny, "passthrough"> | null | undefined;
3134
+ template_id?: string | null | undefined;
3135
+ preheader?: string | null | undefined;
3136
+ label?: string | null | undefined;
3137
+ } | {
3138
+ kind: "delay";
3139
+ next: string | null;
3140
+ wait: {
3141
+ mode: "duration";
3142
+ seconds: number;
3143
+ } | {
3144
+ at: string;
3145
+ mode: "time_of_day";
3146
+ } | {
3147
+ at: string;
3148
+ mode: "weekday";
3149
+ weekday: number;
3150
+ } | {
3151
+ at: string;
3152
+ on: string;
3153
+ mode: "date";
3154
+ passed: "skip" | "stop";
3155
+ } | {
3156
+ at: string;
3157
+ key: string;
3158
+ offset_days: number;
3159
+ mode: "date_property";
3160
+ passed: "skip" | "stop" | "continue";
3161
+ };
3162
+ label?: string | null | undefined;
3163
+ } | {
3164
+ filter: _marlinjai_mail_contract.SegmentFilter;
3165
+ kind: "condition";
3166
+ yes: string | null;
3167
+ no: string | null;
3168
+ label?: string | null | undefined;
3169
+ wait_for?: {
3170
+ up_to_s: number;
3171
+ on_timeout: "yes" | "no";
3172
+ } | null | undefined;
3173
+ } | {
3174
+ kind: "split";
3175
+ branches: {
3176
+ key: string;
3177
+ next: string | null;
3178
+ weight: number;
3179
+ }[];
3180
+ label?: string | null | undefined;
3181
+ } | {
3182
+ kind: "goto";
3183
+ target: string | null;
3184
+ label?: string | null | undefined;
3185
+ } | {
3186
+ kind: "webhook";
3187
+ next: string | null;
3188
+ endpoint_id: string | null;
3189
+ label?: string | null | undefined;
3190
+ payload?: _marlinjai_mail_contract.JsonValue | undefined;
3191
+ } | {
3192
+ subject: string;
3193
+ kind: "notify";
3194
+ to: "owner" | "admins" | {
3195
+ member_id: string;
3196
+ };
3197
+ next: string | null;
3198
+ body: string;
3199
+ label?: string | null | undefined;
3200
+ } | {
3201
+ kind: "add_tag";
3202
+ tag: string;
3203
+ next: string | null;
3204
+ label?: string | null | undefined;
3205
+ } | {
3206
+ kind: "remove_tag";
3207
+ tag: string;
3208
+ next: string | null;
3209
+ label?: string | null | undefined;
3210
+ } | {
3211
+ value: _marlinjai_mail_contract.JsonValue;
3212
+ key: string;
3213
+ kind: "set_property";
3214
+ next: string | null;
3215
+ label?: string | null | undefined;
3216
+ } | {
3217
+ kind: "subscribe_topic";
3218
+ topic: string;
3219
+ next: string | null;
3220
+ label?: string | null | undefined;
3221
+ } | {
3222
+ kind: "unsubscribe";
3223
+ next: string | null;
3224
+ scope: "topic" | "all";
3225
+ label?: string | null | undefined;
3226
+ } | {
3227
+ kind: "exit";
3228
+ label?: string | null | undefined;
3229
+ }>;
3230
+ };
3231
+ published_flow: {
3232
+ triggers: ({
3233
+ kind: "topic_subscribed";
3234
+ topic: string;
3235
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3236
+ } | {
3237
+ kind: "form_confirmed";
3238
+ form_id: string;
3239
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3240
+ } | {
3241
+ kind: "tag_added";
3242
+ tag: string;
3243
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3244
+ } | {
3245
+ key: string;
3246
+ kind: "property_changed";
3247
+ to?: _marlinjai_mail_contract.JsonValue | undefined;
3248
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3249
+ } | {
3250
+ name: string;
3251
+ kind: "event";
3252
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3253
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3254
+ } | {
3255
+ kind: "manual";
3256
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3257
+ } | {
3258
+ at: string;
3259
+ key: string;
3260
+ kind: "date_anniversary";
3261
+ offset_days: number;
3262
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3263
+ } | {
3264
+ at: string;
3265
+ kind: "exact_date";
3266
+ on: string;
3267
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3268
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3269
+ } | {
3270
+ kind: "segment_entered";
3271
+ segment_id: string;
3272
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3273
+ } | {
3274
+ kind: "link_clicked";
3275
+ mailing_id: string;
3276
+ url?: string | undefined;
3277
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3278
+ })[];
3279
+ entry: string | null;
3280
+ steps: Record<string, {
3281
+ subject: string;
3282
+ kind: "email";
3283
+ next: string | null;
3284
+ document?: zod.objectOutputType<{
3285
+ version: zod.ZodEnum<["1.0", "1.1"]>;
3286
+ metadata: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
3287
+ sections: zod.ZodArray<zod.ZodRecord<zod.ZodString, zod.ZodUnknown>, "many">;
3288
+ }, zod.ZodTypeAny, "passthrough"> | null | undefined;
3289
+ template_id?: string | null | undefined;
3290
+ preheader?: string | null | undefined;
3291
+ label?: string | null | undefined;
3292
+ } | {
3293
+ kind: "delay";
3294
+ next: string | null;
3295
+ wait: {
3296
+ mode: "duration";
3297
+ seconds: number;
3298
+ } | {
3299
+ at: string;
3300
+ mode: "time_of_day";
3301
+ } | {
3302
+ at: string;
3303
+ mode: "weekday";
3304
+ weekday: number;
3305
+ } | {
3306
+ at: string;
3307
+ on: string;
3308
+ mode: "date";
3309
+ passed: "skip" | "stop";
3310
+ } | {
3311
+ at: string;
3312
+ key: string;
3313
+ offset_days: number;
3314
+ mode: "date_property";
3315
+ passed: "skip" | "stop" | "continue";
3316
+ };
3317
+ label?: string | null | undefined;
3318
+ } | {
3319
+ filter: _marlinjai_mail_contract.SegmentFilter;
3320
+ kind: "condition";
3321
+ yes: string | null;
3322
+ no: string | null;
3323
+ label?: string | null | undefined;
3324
+ wait_for?: {
3325
+ up_to_s: number;
3326
+ on_timeout: "yes" | "no";
3327
+ } | null | undefined;
3328
+ } | {
3329
+ kind: "split";
3330
+ branches: {
3331
+ key: string;
3332
+ next: string | null;
3333
+ weight: number;
3334
+ }[];
3335
+ label?: string | null | undefined;
3336
+ } | {
3337
+ kind: "goto";
3338
+ target: string | null;
3339
+ label?: string | null | undefined;
3340
+ } | {
3341
+ kind: "webhook";
3342
+ next: string | null;
3343
+ endpoint_id: string | null;
3344
+ label?: string | null | undefined;
3345
+ payload?: _marlinjai_mail_contract.JsonValue | undefined;
3346
+ } | {
3347
+ subject: string;
3348
+ kind: "notify";
3349
+ to: "owner" | "admins" | {
3350
+ member_id: string;
3351
+ };
3352
+ next: string | null;
3353
+ body: string;
3354
+ label?: string | null | undefined;
3355
+ } | {
3356
+ kind: "add_tag";
3357
+ tag: string;
3358
+ next: string | null;
3359
+ label?: string | null | undefined;
3360
+ } | {
3361
+ kind: "remove_tag";
3362
+ tag: string;
3363
+ next: string | null;
3364
+ label?: string | null | undefined;
3365
+ } | {
3366
+ value: _marlinjai_mail_contract.JsonValue;
3367
+ key: string;
3368
+ kind: "set_property";
3369
+ next: string | null;
3370
+ label?: string | null | undefined;
3371
+ } | {
3372
+ kind: "subscribe_topic";
3373
+ topic: string;
3374
+ next: string | null;
3375
+ label?: string | null | undefined;
3376
+ } | {
3377
+ kind: "unsubscribe";
3378
+ next: string | null;
3379
+ scope: "topic" | "all";
3380
+ label?: string | null | undefined;
3381
+ } | {
3382
+ kind: "exit";
3383
+ label?: string | null | undefined;
3384
+ }>;
3385
+ } | null;
3386
+ }>;
3387
+ /** Saves the draft. `base_version` is the draft version you loaded; a stale one is `conflict` (409). */
3388
+ update: (id: string, body: RouteBody<"automations.update">, opts?: RequestOpts) => Promise<{
3389
+ status: "archived" | "draft" | "paused" | "active";
3390
+ id: string;
3391
+ name: string;
3392
+ created_at: string;
3393
+ updated_at: string;
3394
+ topic: string;
3395
+ provider_id: string | null;
3396
+ counts: {
3397
+ failed: number;
3398
+ completed: number;
3399
+ started: number;
3400
+ in_progress: number;
3401
+ exited: number;
3402
+ };
3403
+ settings: {
3404
+ re_entry: "off" | "after_exit";
3405
+ re_entry_cooldown_s?: number | null | undefined;
3406
+ quiet_hours?: {
3407
+ start: string;
3408
+ end: string;
3409
+ weekdays?: number[] | null | undefined;
3410
+ } | null | undefined;
3411
+ exit_filter?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3412
+ };
3413
+ published_version: number | null;
3414
+ draft_version: number;
3415
+ published_at: string | null;
3416
+ flow: {
3417
+ triggers: ({
3418
+ kind: "topic_subscribed";
3419
+ topic: string;
3420
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3421
+ } | {
3422
+ kind: "form_confirmed";
3423
+ form_id: string;
3424
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3425
+ } | {
3426
+ kind: "tag_added";
3427
+ tag: string;
3428
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3429
+ } | {
3430
+ key: string;
3431
+ kind: "property_changed";
3432
+ to?: _marlinjai_mail_contract.JsonValue | undefined;
3433
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3434
+ } | {
3435
+ name: string;
3436
+ kind: "event";
3437
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3438
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3439
+ } | {
3440
+ kind: "manual";
3441
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3442
+ } | {
3443
+ at: string;
3444
+ key: string;
3445
+ kind: "date_anniversary";
3446
+ offset_days: number;
3447
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3448
+ } | {
3449
+ at: string;
3450
+ kind: "exact_date";
3451
+ on: string;
3452
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3453
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3454
+ } | {
3455
+ kind: "segment_entered";
3456
+ segment_id: string;
3457
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3458
+ } | {
3459
+ kind: "link_clicked";
3460
+ mailing_id: string;
3461
+ url?: string | undefined;
3462
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3463
+ })[];
3464
+ entry: string | null;
3465
+ steps: Record<string, {
3466
+ subject: string;
3467
+ kind: "email";
3468
+ next: string | null;
3469
+ document?: zod.objectOutputType<{
3470
+ version: zod.ZodEnum<["1.0", "1.1"]>;
3471
+ metadata: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
3472
+ sections: zod.ZodArray<zod.ZodRecord<zod.ZodString, zod.ZodUnknown>, "many">;
3473
+ }, zod.ZodTypeAny, "passthrough"> | null | undefined;
3474
+ template_id?: string | null | undefined;
3475
+ preheader?: string | null | undefined;
3476
+ label?: string | null | undefined;
3477
+ } | {
3478
+ kind: "delay";
3479
+ next: string | null;
3480
+ wait: {
3481
+ mode: "duration";
3482
+ seconds: number;
3483
+ } | {
3484
+ at: string;
3485
+ mode: "time_of_day";
3486
+ } | {
3487
+ at: string;
3488
+ mode: "weekday";
3489
+ weekday: number;
3490
+ } | {
3491
+ at: string;
3492
+ on: string;
3493
+ mode: "date";
3494
+ passed: "skip" | "stop";
3495
+ } | {
3496
+ at: string;
3497
+ key: string;
3498
+ offset_days: number;
3499
+ mode: "date_property";
3500
+ passed: "skip" | "stop" | "continue";
3501
+ };
3502
+ label?: string | null | undefined;
3503
+ } | {
3504
+ filter: _marlinjai_mail_contract.SegmentFilter;
3505
+ kind: "condition";
3506
+ yes: string | null;
3507
+ no: string | null;
3508
+ label?: string | null | undefined;
3509
+ wait_for?: {
3510
+ up_to_s: number;
3511
+ on_timeout: "yes" | "no";
3512
+ } | null | undefined;
3513
+ } | {
3514
+ kind: "split";
3515
+ branches: {
3516
+ key: string;
3517
+ next: string | null;
3518
+ weight: number;
3519
+ }[];
3520
+ label?: string | null | undefined;
3521
+ } | {
3522
+ kind: "goto";
3523
+ target: string | null;
3524
+ label?: string | null | undefined;
3525
+ } | {
3526
+ kind: "webhook";
3527
+ next: string | null;
3528
+ endpoint_id: string | null;
3529
+ label?: string | null | undefined;
3530
+ payload?: _marlinjai_mail_contract.JsonValue | undefined;
3531
+ } | {
3532
+ subject: string;
3533
+ kind: "notify";
3534
+ to: "owner" | "admins" | {
3535
+ member_id: string;
3536
+ };
3537
+ next: string | null;
3538
+ body: string;
3539
+ label?: string | null | undefined;
3540
+ } | {
3541
+ kind: "add_tag";
3542
+ tag: string;
3543
+ next: string | null;
3544
+ label?: string | null | undefined;
3545
+ } | {
3546
+ kind: "remove_tag";
3547
+ tag: string;
3548
+ next: string | null;
3549
+ label?: string | null | undefined;
3550
+ } | {
3551
+ value: _marlinjai_mail_contract.JsonValue;
3552
+ key: string;
3553
+ kind: "set_property";
3554
+ next: string | null;
3555
+ label?: string | null | undefined;
3556
+ } | {
3557
+ kind: "subscribe_topic";
3558
+ topic: string;
3559
+ next: string | null;
3560
+ label?: string | null | undefined;
3561
+ } | {
3562
+ kind: "unsubscribe";
3563
+ next: string | null;
3564
+ scope: "topic" | "all";
3565
+ label?: string | null | undefined;
3566
+ } | {
3567
+ kind: "exit";
3568
+ label?: string | null | undefined;
3569
+ }>;
3570
+ };
3571
+ published_flow: {
3572
+ triggers: ({
3573
+ kind: "topic_subscribed";
3574
+ topic: string;
3575
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3576
+ } | {
3577
+ kind: "form_confirmed";
3578
+ form_id: string;
3579
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3580
+ } | {
3581
+ kind: "tag_added";
3582
+ tag: string;
3583
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3584
+ } | {
3585
+ key: string;
3586
+ kind: "property_changed";
3587
+ to?: _marlinjai_mail_contract.JsonValue | undefined;
3588
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3589
+ } | {
3590
+ name: string;
3591
+ kind: "event";
3592
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3593
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3594
+ } | {
3595
+ kind: "manual";
3596
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3597
+ } | {
3598
+ at: string;
3599
+ key: string;
3600
+ kind: "date_anniversary";
3601
+ offset_days: number;
3602
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3603
+ } | {
3604
+ at: string;
3605
+ kind: "exact_date";
3606
+ on: string;
3607
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3608
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3609
+ } | {
3610
+ kind: "segment_entered";
3611
+ segment_id: string;
3612
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3613
+ } | {
3614
+ kind: "link_clicked";
3615
+ mailing_id: string;
3616
+ url?: string | undefined;
3617
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3618
+ })[];
3619
+ entry: string | null;
3620
+ steps: Record<string, {
3621
+ subject: string;
3622
+ kind: "email";
3623
+ next: string | null;
3624
+ document?: zod.objectOutputType<{
3625
+ version: zod.ZodEnum<["1.0", "1.1"]>;
3626
+ metadata: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
3627
+ sections: zod.ZodArray<zod.ZodRecord<zod.ZodString, zod.ZodUnknown>, "many">;
3628
+ }, zod.ZodTypeAny, "passthrough"> | null | undefined;
3629
+ template_id?: string | null | undefined;
3630
+ preheader?: string | null | undefined;
3631
+ label?: string | null | undefined;
3632
+ } | {
3633
+ kind: "delay";
3634
+ next: string | null;
3635
+ wait: {
3636
+ mode: "duration";
3637
+ seconds: number;
3638
+ } | {
3639
+ at: string;
3640
+ mode: "time_of_day";
3641
+ } | {
3642
+ at: string;
3643
+ mode: "weekday";
3644
+ weekday: number;
3645
+ } | {
3646
+ at: string;
3647
+ on: string;
3648
+ mode: "date";
3649
+ passed: "skip" | "stop";
3650
+ } | {
3651
+ at: string;
3652
+ key: string;
3653
+ offset_days: number;
3654
+ mode: "date_property";
3655
+ passed: "skip" | "stop" | "continue";
3656
+ };
3657
+ label?: string | null | undefined;
3658
+ } | {
3659
+ filter: _marlinjai_mail_contract.SegmentFilter;
3660
+ kind: "condition";
3661
+ yes: string | null;
3662
+ no: string | null;
3663
+ label?: string | null | undefined;
3664
+ wait_for?: {
3665
+ up_to_s: number;
3666
+ on_timeout: "yes" | "no";
3667
+ } | null | undefined;
3668
+ } | {
3669
+ kind: "split";
3670
+ branches: {
3671
+ key: string;
3672
+ next: string | null;
3673
+ weight: number;
3674
+ }[];
3675
+ label?: string | null | undefined;
3676
+ } | {
3677
+ kind: "goto";
3678
+ target: string | null;
3679
+ label?: string | null | undefined;
3680
+ } | {
3681
+ kind: "webhook";
3682
+ next: string | null;
3683
+ endpoint_id: string | null;
3684
+ label?: string | null | undefined;
3685
+ payload?: _marlinjai_mail_contract.JsonValue | undefined;
3686
+ } | {
3687
+ subject: string;
3688
+ kind: "notify";
3689
+ to: "owner" | "admins" | {
3690
+ member_id: string;
3691
+ };
3692
+ next: string | null;
3693
+ body: string;
3694
+ label?: string | null | undefined;
3695
+ } | {
3696
+ kind: "add_tag";
3697
+ tag: string;
3698
+ next: string | null;
3699
+ label?: string | null | undefined;
3700
+ } | {
3701
+ kind: "remove_tag";
3702
+ tag: string;
3703
+ next: string | null;
3704
+ label?: string | null | undefined;
3705
+ } | {
3706
+ value: _marlinjai_mail_contract.JsonValue;
3707
+ key: string;
3708
+ kind: "set_property";
3709
+ next: string | null;
3710
+ label?: string | null | undefined;
3711
+ } | {
3712
+ kind: "subscribe_topic";
3713
+ topic: string;
3714
+ next: string | null;
3715
+ label?: string | null | undefined;
3716
+ } | {
3717
+ kind: "unsubscribe";
3718
+ next: string | null;
3719
+ scope: "topic" | "all";
3720
+ label?: string | null | undefined;
3721
+ } | {
3722
+ kind: "exit";
3723
+ label?: string | null | undefined;
3724
+ }>;
3725
+ } | null;
3726
+ }>;
3727
+ delete: (id: string, opts?: RequestOpts) => Promise<{
3728
+ ok: true;
3729
+ }>;
3730
+ /** Every problem that stops the draft from being published, with nothing saved. */
3731
+ validate: (id: string, body?: RouteBody<"automations.validate">, opts?: RequestOpts) => Promise<{
3732
+ issues: {
3733
+ code: "unknown_reference" | "tracking_disabled" | "invalid_value" | "missing_trigger" | "duplicate_trigger" | "empty_flow" | "dangling_next" | "unreachable_step" | "tight_loop" | "empty_email" | "not_chosen" | "too_many_steps" | "filter_too_deep" | "unsupported_field" | "unsupported_operator" | "cooldown_without_reentry" | "invalid_quiet_hours" | "not_a_date_property" | "date_in_the_past";
3734
+ path: (string | number)[];
3735
+ message: string;
3736
+ step_id: string | null;
3737
+ }[];
3738
+ ok: boolean;
3739
+ }>;
3740
+ /**
3741
+ * Publishes the draft. On a live automation the first call answers
3742
+ * `published: false` with the people who would have to move; call again
3743
+ * with `confirm: true` to go ahead.
3744
+ */
3745
+ publish: (id: string, body?: RouteBody<"automations.publish">, opts?: RequestOpts) => Promise<{
3746
+ issues: {
3747
+ code: "unknown_reference" | "tracking_disabled" | "invalid_value" | "missing_trigger" | "duplicate_trigger" | "empty_flow" | "dangling_next" | "unreachable_step" | "tight_loop" | "empty_email" | "not_chosen" | "too_many_steps" | "filter_too_deep" | "unsupported_field" | "unsupported_operator" | "cooldown_without_reentry" | "invalid_quiet_hours" | "not_a_date_property" | "date_in_the_past";
3748
+ path: (string | number)[];
3749
+ message: string;
3750
+ step_id: string | null;
3751
+ }[];
3752
+ automation: {
3753
+ status: "archived" | "draft" | "paused" | "active";
3754
+ id: string;
3755
+ name: string;
3756
+ created_at: string;
3757
+ updated_at: string;
3758
+ topic: string;
3759
+ provider_id: string | null;
3760
+ counts: {
3761
+ failed: number;
3762
+ completed: number;
3763
+ started: number;
3764
+ in_progress: number;
3765
+ exited: number;
3766
+ };
3767
+ settings: {
3768
+ re_entry: "off" | "after_exit";
3769
+ re_entry_cooldown_s?: number | null | undefined;
3770
+ quiet_hours?: {
3771
+ start: string;
3772
+ end: string;
3773
+ weekdays?: number[] | null | undefined;
3774
+ } | null | undefined;
3775
+ exit_filter?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3776
+ };
3777
+ published_version: number | null;
3778
+ draft_version: number;
3779
+ published_at: string | null;
3780
+ };
3781
+ moves: {
3782
+ step_id: string;
3783
+ change: "removed" | "delay_changed" | "kind_changed";
3784
+ waiting: number;
3785
+ destination: string | null;
3786
+ }[];
3787
+ backfill: number;
3788
+ published: boolean;
3789
+ }>;
3790
+ pause: (id: string, opts?: RequestOpts) => Promise<{
3791
+ status: "archived" | "draft" | "paused" | "active";
3792
+ id: string;
3793
+ name: string;
3794
+ created_at: string;
3795
+ updated_at: string;
3796
+ topic: string;
3797
+ provider_id: string | null;
3798
+ counts: {
3799
+ failed: number;
3800
+ completed: number;
3801
+ started: number;
3802
+ in_progress: number;
3803
+ exited: number;
3804
+ };
3805
+ settings: {
3806
+ re_entry: "off" | "after_exit";
3807
+ re_entry_cooldown_s?: number | null | undefined;
3808
+ quiet_hours?: {
3809
+ start: string;
3810
+ end: string;
3811
+ weekdays?: number[] | null | undefined;
3812
+ } | null | undefined;
3813
+ exit_filter?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3814
+ };
3815
+ published_version: number | null;
3816
+ draft_version: number;
3817
+ published_at: string | null;
3818
+ }>;
3819
+ resume: (id: string, opts?: RequestOpts) => Promise<{
3820
+ status: "archived" | "draft" | "paused" | "active";
3821
+ id: string;
3822
+ name: string;
3823
+ created_at: string;
3824
+ updated_at: string;
3825
+ topic: string;
3826
+ provider_id: string | null;
3827
+ counts: {
3828
+ failed: number;
3829
+ completed: number;
3830
+ started: number;
3831
+ in_progress: number;
3832
+ exited: number;
3833
+ };
3834
+ settings: {
3835
+ re_entry: "off" | "after_exit";
3836
+ re_entry_cooldown_s?: number | null | undefined;
3837
+ quiet_hours?: {
3838
+ start: string;
3839
+ end: string;
3840
+ weekdays?: number[] | null | undefined;
3841
+ } | null | undefined;
3842
+ exit_filter?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3843
+ };
3844
+ published_version: number | null;
3845
+ draft_version: number;
3846
+ published_at: string | null;
3847
+ }>;
3848
+ archive: (id: string, opts?: RequestOpts) => Promise<{
3849
+ status: "archived" | "draft" | "paused" | "active";
3850
+ id: string;
3851
+ name: string;
3852
+ created_at: string;
3853
+ updated_at: string;
3854
+ topic: string;
3855
+ provider_id: string | null;
3856
+ counts: {
3857
+ failed: number;
3858
+ completed: number;
3859
+ started: number;
3860
+ in_progress: number;
3861
+ exited: number;
3862
+ };
3863
+ settings: {
3864
+ re_entry: "off" | "after_exit";
3865
+ re_entry_cooldown_s?: number | null | undefined;
3866
+ quiet_hours?: {
3867
+ start: string;
3868
+ end: string;
3869
+ weekdays?: number[] | null | undefined;
3870
+ } | null | undefined;
3871
+ exit_filter?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3872
+ };
3873
+ published_version: number | null;
3874
+ draft_version: number;
3875
+ published_at: string | null;
3876
+ }>;
3877
+ duplicate: (id: string, body?: RouteBody<"automations.duplicate">, opts?: RequestOpts) => Promise<{
3878
+ status: "archived" | "draft" | "paused" | "active";
3879
+ id: string;
3880
+ name: string;
3881
+ created_at: string;
3882
+ updated_at: string;
3883
+ topic: string;
3884
+ provider_id: string | null;
3885
+ counts: {
3886
+ failed: number;
3887
+ completed: number;
3888
+ started: number;
3889
+ in_progress: number;
3890
+ exited: number;
3891
+ };
3892
+ settings: {
3893
+ re_entry: "off" | "after_exit";
3894
+ re_entry_cooldown_s?: number | null | undefined;
3895
+ quiet_hours?: {
3896
+ start: string;
3897
+ end: string;
3898
+ weekdays?: number[] | null | undefined;
3899
+ } | null | undefined;
3900
+ exit_filter?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3901
+ };
3902
+ published_version: number | null;
3903
+ draft_version: number;
3904
+ published_at: string | null;
3905
+ flow: {
3906
+ triggers: ({
3907
+ kind: "topic_subscribed";
3908
+ topic: string;
3909
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3910
+ } | {
3911
+ kind: "form_confirmed";
3912
+ form_id: string;
3913
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3914
+ } | {
3915
+ kind: "tag_added";
3916
+ tag: string;
3917
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3918
+ } | {
3919
+ key: string;
3920
+ kind: "property_changed";
3921
+ to?: _marlinjai_mail_contract.JsonValue | undefined;
3922
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3923
+ } | {
3924
+ name: string;
3925
+ kind: "event";
3926
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3927
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3928
+ } | {
3929
+ kind: "manual";
3930
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3931
+ } | {
3932
+ at: string;
3933
+ key: string;
3934
+ kind: "date_anniversary";
3935
+ offset_days: number;
3936
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3937
+ } | {
3938
+ at: string;
3939
+ kind: "exact_date";
3940
+ on: string;
3941
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3942
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3943
+ } | {
3944
+ kind: "segment_entered";
3945
+ segment_id: string;
3946
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3947
+ } | {
3948
+ kind: "link_clicked";
3949
+ mailing_id: string;
3950
+ url?: string | undefined;
3951
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
3952
+ })[];
3953
+ entry: string | null;
3954
+ steps: Record<string, {
3955
+ subject: string;
3956
+ kind: "email";
3957
+ next: string | null;
3958
+ document?: zod.objectOutputType<{
3959
+ version: zod.ZodEnum<["1.0", "1.1"]>;
3960
+ metadata: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
3961
+ sections: zod.ZodArray<zod.ZodRecord<zod.ZodString, zod.ZodUnknown>, "many">;
3962
+ }, zod.ZodTypeAny, "passthrough"> | null | undefined;
3963
+ template_id?: string | null | undefined;
3964
+ preheader?: string | null | undefined;
3965
+ label?: string | null | undefined;
3966
+ } | {
3967
+ kind: "delay";
3968
+ next: string | null;
3969
+ wait: {
3970
+ mode: "duration";
3971
+ seconds: number;
3972
+ } | {
3973
+ at: string;
3974
+ mode: "time_of_day";
3975
+ } | {
3976
+ at: string;
3977
+ mode: "weekday";
3978
+ weekday: number;
3979
+ } | {
3980
+ at: string;
3981
+ on: string;
3982
+ mode: "date";
3983
+ passed: "skip" | "stop";
3984
+ } | {
3985
+ at: string;
3986
+ key: string;
3987
+ offset_days: number;
3988
+ mode: "date_property";
3989
+ passed: "skip" | "stop" | "continue";
3990
+ };
3991
+ label?: string | null | undefined;
3992
+ } | {
3993
+ filter: _marlinjai_mail_contract.SegmentFilter;
3994
+ kind: "condition";
3995
+ yes: string | null;
3996
+ no: string | null;
3997
+ label?: string | null | undefined;
3998
+ wait_for?: {
3999
+ up_to_s: number;
4000
+ on_timeout: "yes" | "no";
4001
+ } | null | undefined;
4002
+ } | {
4003
+ kind: "split";
4004
+ branches: {
4005
+ key: string;
4006
+ next: string | null;
4007
+ weight: number;
4008
+ }[];
4009
+ label?: string | null | undefined;
4010
+ } | {
4011
+ kind: "goto";
4012
+ target: string | null;
4013
+ label?: string | null | undefined;
4014
+ } | {
4015
+ kind: "webhook";
4016
+ next: string | null;
4017
+ endpoint_id: string | null;
4018
+ label?: string | null | undefined;
4019
+ payload?: _marlinjai_mail_contract.JsonValue | undefined;
4020
+ } | {
4021
+ subject: string;
4022
+ kind: "notify";
4023
+ to: "owner" | "admins" | {
4024
+ member_id: string;
4025
+ };
4026
+ next: string | null;
4027
+ body: string;
4028
+ label?: string | null | undefined;
4029
+ } | {
4030
+ kind: "add_tag";
4031
+ tag: string;
4032
+ next: string | null;
4033
+ label?: string | null | undefined;
4034
+ } | {
4035
+ kind: "remove_tag";
4036
+ tag: string;
4037
+ next: string | null;
4038
+ label?: string | null | undefined;
4039
+ } | {
4040
+ value: _marlinjai_mail_contract.JsonValue;
4041
+ key: string;
4042
+ kind: "set_property";
4043
+ next: string | null;
4044
+ label?: string | null | undefined;
4045
+ } | {
4046
+ kind: "subscribe_topic";
4047
+ topic: string;
4048
+ next: string | null;
4049
+ label?: string | null | undefined;
4050
+ } | {
4051
+ kind: "unsubscribe";
4052
+ next: string | null;
4053
+ scope: "topic" | "all";
4054
+ label?: string | null | undefined;
4055
+ } | {
4056
+ kind: "exit";
4057
+ label?: string | null | undefined;
4058
+ }>;
4059
+ };
4060
+ published_flow: {
4061
+ triggers: ({
4062
+ kind: "topic_subscribed";
4063
+ topic: string;
4064
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4065
+ } | {
4066
+ kind: "form_confirmed";
4067
+ form_id: string;
4068
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4069
+ } | {
4070
+ kind: "tag_added";
4071
+ tag: string;
4072
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4073
+ } | {
4074
+ key: string;
4075
+ kind: "property_changed";
4076
+ to?: _marlinjai_mail_contract.JsonValue | undefined;
4077
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4078
+ } | {
4079
+ name: string;
4080
+ kind: "event";
4081
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4082
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4083
+ } | {
4084
+ kind: "manual";
4085
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4086
+ } | {
4087
+ at: string;
4088
+ key: string;
4089
+ kind: "date_anniversary";
4090
+ offset_days: number;
4091
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4092
+ } | {
4093
+ at: string;
4094
+ kind: "exact_date";
4095
+ on: string;
4096
+ where?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4097
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4098
+ } | {
4099
+ kind: "segment_entered";
4100
+ segment_id: string;
4101
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4102
+ } | {
4103
+ kind: "link_clicked";
4104
+ mailing_id: string;
4105
+ url?: string | undefined;
4106
+ exclude?: _marlinjai_mail_contract.SegmentFilter | null | undefined;
4107
+ })[];
4108
+ entry: string | null;
4109
+ steps: Record<string, {
4110
+ subject: string;
4111
+ kind: "email";
4112
+ next: string | null;
4113
+ document?: zod.objectOutputType<{
4114
+ version: zod.ZodEnum<["1.0", "1.1"]>;
4115
+ metadata: zod.ZodRecord<zod.ZodString, zod.ZodUnknown>;
4116
+ sections: zod.ZodArray<zod.ZodRecord<zod.ZodString, zod.ZodUnknown>, "many">;
4117
+ }, zod.ZodTypeAny, "passthrough"> | null | undefined;
4118
+ template_id?: string | null | undefined;
4119
+ preheader?: string | null | undefined;
4120
+ label?: string | null | undefined;
4121
+ } | {
4122
+ kind: "delay";
4123
+ next: string | null;
4124
+ wait: {
4125
+ mode: "duration";
4126
+ seconds: number;
4127
+ } | {
4128
+ at: string;
4129
+ mode: "time_of_day";
4130
+ } | {
4131
+ at: string;
4132
+ mode: "weekday";
4133
+ weekday: number;
4134
+ } | {
4135
+ at: string;
4136
+ on: string;
4137
+ mode: "date";
4138
+ passed: "skip" | "stop";
4139
+ } | {
4140
+ at: string;
4141
+ key: string;
4142
+ offset_days: number;
4143
+ mode: "date_property";
4144
+ passed: "skip" | "stop" | "continue";
4145
+ };
4146
+ label?: string | null | undefined;
4147
+ } | {
4148
+ filter: _marlinjai_mail_contract.SegmentFilter;
4149
+ kind: "condition";
4150
+ yes: string | null;
4151
+ no: string | null;
4152
+ label?: string | null | undefined;
4153
+ wait_for?: {
4154
+ up_to_s: number;
4155
+ on_timeout: "yes" | "no";
4156
+ } | null | undefined;
4157
+ } | {
4158
+ kind: "split";
4159
+ branches: {
4160
+ key: string;
4161
+ next: string | null;
4162
+ weight: number;
4163
+ }[];
4164
+ label?: string | null | undefined;
4165
+ } | {
4166
+ kind: "goto";
4167
+ target: string | null;
4168
+ label?: string | null | undefined;
4169
+ } | {
4170
+ kind: "webhook";
4171
+ next: string | null;
4172
+ endpoint_id: string | null;
4173
+ label?: string | null | undefined;
4174
+ payload?: _marlinjai_mail_contract.JsonValue | undefined;
4175
+ } | {
4176
+ subject: string;
4177
+ kind: "notify";
4178
+ to: "owner" | "admins" | {
4179
+ member_id: string;
4180
+ };
4181
+ next: string | null;
4182
+ body: string;
4183
+ label?: string | null | undefined;
4184
+ } | {
4185
+ kind: "add_tag";
4186
+ tag: string;
4187
+ next: string | null;
4188
+ label?: string | null | undefined;
4189
+ } | {
4190
+ kind: "remove_tag";
4191
+ tag: string;
4192
+ next: string | null;
4193
+ label?: string | null | undefined;
4194
+ } | {
4195
+ value: _marlinjai_mail_contract.JsonValue;
4196
+ key: string;
4197
+ kind: "set_property";
4198
+ next: string | null;
4199
+ label?: string | null | undefined;
4200
+ } | {
4201
+ kind: "subscribe_topic";
4202
+ topic: string;
4203
+ next: string | null;
4204
+ label?: string | null | undefined;
4205
+ } | {
4206
+ kind: "unsubscribe";
4207
+ next: string | null;
4208
+ scope: "topic" | "all";
4209
+ label?: string | null | undefined;
4210
+ } | {
4211
+ kind: "exit";
4212
+ label?: string | null | undefined;
4213
+ }>;
4214
+ } | null;
4215
+ }>;
4216
+ /** Enters people by hand; each answer says entered, or refused with the reason. */
4217
+ enroll: (id: string, body: RouteBody<"automations.enroll">, opts?: RequestOpts) => Promise<{
4218
+ entered: number;
4219
+ refused: number;
4220
+ results: {
4221
+ reason: "suppressed" | "not_subscribed" | "unknown_contact" | "already_inside" | "re_entry_off" | "in_cooldown" | "excluded" | "not_active" | null;
4222
+ contact_id: string | null;
4223
+ email: string | null;
4224
+ external_id: string | null;
4225
+ entered: boolean;
4226
+ run_id: string | null;
4227
+ }[];
4228
+ }>;
4229
+ testEmail: (id: string, stepId: string, body: RouteBody<"automations.testEmail">, opts?: RequestOpts) => Promise<{
4230
+ message_id: string;
4231
+ provider_message_id: string | null;
4232
+ }>;
4233
+ runs: (id: string, query?: RouteQuery<"automations.runs">, opts?: RequestOpts) => Promise<{
4234
+ data: {
4235
+ status: "failed" | "completed" | "active" | "exited" | "waiting";
4236
+ id: string;
4237
+ version: number;
4238
+ automation_id: string;
4239
+ contact_id: string;
4240
+ email: string;
4241
+ last_error: string | null;
4242
+ external_id: string | null;
4243
+ current_step_id: string | null;
4244
+ next_action_at: string | null;
4245
+ wait_reason: "sending" | "delay" | "condition" | "quiet_hours" | "plan_limit" | null;
4246
+ end_reason: string | null;
4247
+ entered_at: string;
4248
+ ended_at: string | null;
4249
+ }[];
4250
+ next_cursor: string | null;
4251
+ }>;
4252
+ /** One person's journey, step by step. */
4253
+ run: (id: string, runId: string, opts?: RequestOpts) => Promise<{
4254
+ steps: {
4255
+ started_at: string;
4256
+ finished_at: string | null;
4257
+ outcome: Record<string, _marlinjai_mail_contract.JsonValue>;
4258
+ step_id: string;
4259
+ step_kind: "email" | "delay" | "condition" | "add_tag" | "remove_tag" | "set_property" | "subscribe_topic" | "unsubscribe" | "exit" | "split" | "goto" | "webhook" | "notify";
4260
+ visit: number;
4261
+ }[];
4262
+ run: {
4263
+ status: "failed" | "completed" | "active" | "exited" | "waiting";
4264
+ id: string;
4265
+ version: number;
4266
+ automation_id: string;
4267
+ contact_id: string;
4268
+ email: string;
4269
+ last_error: string | null;
4270
+ external_id: string | null;
4271
+ current_step_id: string | null;
4272
+ next_action_at: string | null;
4273
+ wait_reason: "sending" | "delay" | "condition" | "quiet_hours" | "plan_limit" | null;
4274
+ end_reason: string | null;
4275
+ entered_at: string;
4276
+ ended_at: string | null;
4277
+ };
4278
+ }>;
4279
+ exitRun: (id: string, runId: string, body?: RouteBody<"automations.exitRun">, opts?: RequestOpts) => Promise<{
4280
+ status: "failed" | "completed" | "active" | "exited" | "waiting";
4281
+ id: string;
4282
+ version: number;
4283
+ automation_id: string;
4284
+ contact_id: string;
4285
+ email: string;
4286
+ last_error: string | null;
4287
+ external_id: string | null;
4288
+ current_step_id: string | null;
4289
+ next_action_at: string | null;
4290
+ wait_reason: "sending" | "delay" | "condition" | "quiet_hours" | "plan_limit" | null;
4291
+ end_reason: string | null;
4292
+ entered_at: string;
4293
+ ended_at: string | null;
4294
+ }>;
4295
+ report: (id: string, opts?: RequestOpts) => Promise<{
4296
+ counts: {
4297
+ failed: number;
4298
+ completed: number;
4299
+ started: number;
4300
+ in_progress: number;
4301
+ exited: number;
4302
+ };
4303
+ steps: {
4304
+ mailing_id: string | null;
4305
+ passed: number;
4306
+ branches: Record<string, number>;
4307
+ step_id: string;
4308
+ waiting: number;
4309
+ step_kind: "email" | "delay" | "condition" | "add_tag" | "remove_tag" | "set_property" | "subscribe_topic" | "unsubscribe" | "exit" | "split" | "goto" | "webhook" | "notify";
4310
+ reached: number;
4311
+ }[];
4312
+ end_reasons: Record<string, number>;
4313
+ refusals: Record<string, number>;
4314
+ }>;
4315
+ };
4316
+ events: {
4317
+ /** Tells the service something happened, so the automations waiting for it enter this person. */
4318
+ create: (body: RouteBody<"events.create">, opts?: RequestOpts) => Promise<{
4319
+ data: Record<string, _marlinjai_mail_contract.JsonValue>;
4320
+ id: string;
4321
+ name: string;
4322
+ contact_id: string;
4323
+ entered: number;
4324
+ occurred_at: string;
4325
+ client_event_id: string | null;
4326
+ received_at: string;
4327
+ }>;
4328
+ list: (query?: RouteQuery<"events.list">, opts?: RequestOpts) => Promise<{
4329
+ data: {
4330
+ data: Record<string, _marlinjai_mail_contract.JsonValue>;
4331
+ id: string;
4332
+ name: string;
4333
+ contact_id: string;
4334
+ entered: number;
4335
+ occurred_at: string;
4336
+ client_event_id: string | null;
4337
+ received_at: string;
4338
+ }[];
4339
+ next_cursor: string | null;
4340
+ }>;
4341
+ };
4342
+ };
4343
+ type MailNamespaces = ReturnType<typeof createNamespaces>;
4344
+
4345
+ /**
4346
+ * Operations whose response is a cursor page (`{ data, next_cursor }`). Excludes
4347
+ * the two S4/S5 list routes that return a bare `{ data }` array with no cursor
4348
+ * (`contactProperties.list`, `billing.plans`): those are not paginatable, and the
4349
+ * exclusion is enforced here at compile time, not by convention.
4350
+ */
4351
+ type PaginatableOperationId = {
4352
+ [K in OperationId]: RouteResponse<K> extends Page<unknown> ? K : never;
4353
+ }[OperationId];
4354
+ type PageItem<K extends PaginatableOperationId> = RouteResponse<K> extends Page<infer T> ? T : never;
4355
+ interface PaginateArgs<K extends PaginatableOperationId> {
4356
+ params?: RouteParams<K>;
4357
+ query?: RouteQuery<K>;
4358
+ }
4359
+
4360
+ interface BaseClientOptions {
4361
+ /** The mail service's origin, no trailing slash needed (e.g. `https://mail.lumitra.co`). */
4362
+ baseUrl: string;
4363
+ /** Defaults to the runtime's global `fetch`. Override in tests or to add instrumentation. */
4364
+ fetch?: typeof fetch;
4365
+ /** Per-attempt timeout. A retried call may take up to `(maxRetries + 1) * timeoutMs` plus backoff. */
4366
+ timeoutMs?: number;
4367
+ /** Retries on `RETRYABLE_ERRORS` and network failures only; 4xx errors never retry. */
4368
+ maxRetries?: number;
4369
+ userAgent?: string;
4370
+ /** Validates every response against the contract's zod schema. Disable only to shave latency once you trust the deployment. */
4371
+ validateResponses?: boolean;
4372
+ /** @internal Test-only hook: replaces the backoff sleep. Never set this in application code. */
4373
+ __sleep?: CoreConfig['sleep'];
4374
+ /** @internal Test-only hook: replaces the jitter source. Never set this in application code. */
4375
+ __random?: CoreConfig['random'];
4376
+ }
4377
+ interface MailClientOptions extends BaseClientOptions {
4378
+ /** A workspace API key (`Authorization: Bearer <key>`), scoped to one workspace and to `full`, `send` or `read`. */
4379
+ apiKey: string;
4380
+ }
4381
+ /** Every namespaced method, plus the two escape hatches: `request` for any operation id, `paginate` for cursor lists. */
4382
+ interface MailClient extends MailNamespaces {
4383
+ request<K extends OperationId>(operationId: K, args?: ExecuteArgs<K>, opts?: RequestOpts): Promise<RouteResponse<K>>;
4384
+ paginate<K extends PaginatableOperationId>(operationId: K, args?: PaginateArgs<K>, opts?: RequestOpts): AsyncGenerator<PageItem<K>, void, void>;
4385
+ /**
4386
+ * Checks the service's liveness probe (`HEALTH_PATH`, outside `/v1`, no
4387
+ * credentials sent). Never throws: a network failure or a non-2xx status both
4388
+ * resolve `false`, since this is meant for a caller polling "is it up", not one
4389
+ * that wants a typed error.
4390
+ */
4391
+ health(opts?: {
4392
+ signal?: AbortSignal;
4393
+ }): Promise<boolean>;
4394
+ }
4395
+ /**
4396
+ * A typed client for the Lumitra Mail v1 API, authenticated with a workspace API
4397
+ * key. Safe to use in a browser, a server, or an edge function: it holds only the
4398
+ * key the caller gives it and never assumes a Node runtime.
4399
+ */
4400
+ declare function createMailClient(options: MailClientOptions): MailClient;
4401
+ interface DashboardMailClientOptions extends BaseClientOptions {
4402
+ /** The dashboard's own service token, distinct from any workspace API key. */
4403
+ serviceToken: string;
4404
+ }
4405
+ /** The signed-in person the dashboard is calling on behalf of, for one request. */
4406
+ interface DashboardUserContext {
4407
+ /** The person's auth-brain subject. */
4408
+ subject: string;
4409
+ /**
4410
+ * Omit for a `dashboard`-access route reached before a workspace exists yet
4411
+ * (`workspaces.create`, `workspaces.list`): the service checks membership and
4412
+ * role against this workspace on every other route, so it is required there.
4413
+ */
4414
+ workspaceId?: string;
4415
+ }
4416
+ interface DashboardMailClient {
4417
+ /** Binds the client to one signed-in person and workspace for the calls made through it. */
4418
+ forUser(user: DashboardUserContext): MailClient;
4419
+ }
4420
+ /**
4421
+ * The dashboard variant: authenticates with the dashboard's own service token and
4422
+ * carries the signed-in person's auth-brain subject and workspace on every call,
4423
+ * which the service checks for membership and role. Server-side only, by
4424
+ * construction: constructing this in a browser bundle throws immediately rather
4425
+ * than silently shipping the service token to every visitor.
4426
+ */
4427
+ declare function createDashboardMailClient(options: DashboardMailClientOptions): DashboardMailClient;
4428
+
4429
+ /**
4430
+ * The service refused the request or answered with a non-2xx status. `code` and
4431
+ * `status` come from the parsed `ErrorBody` envelope when the response carried
4432
+ * one; a 5xx with an unparseable body (a proxy's HTML page) still becomes a
4433
+ * `MailApiError` with `code: 'internal_error'` and the raw text in `details.raw`,
4434
+ * so a caller never has to guess what happened.
4435
+ */
4436
+ declare class MailApiError extends Error {
4437
+ readonly code: ErrorCode;
4438
+ readonly status: number;
4439
+ readonly details: Record<string, unknown> | undefined;
4440
+ readonly requestId: string | null;
4441
+ constructor(input: {
4442
+ code: ErrorCode;
4443
+ status: number;
4444
+ message: string;
4445
+ details?: Record<string, unknown>;
4446
+ requestId?: string | null;
4447
+ });
4448
+ }
4449
+ /** The request never reached the service, or the connection failed mid-flight. */
4450
+ declare class MailNetworkError extends Error {
4451
+ readonly cause: unknown;
4452
+ constructor(message: string, cause: unknown);
4453
+ }
4454
+ /** The request exceeded `timeoutMs` before the service answered. */
4455
+ declare class MailTimeoutError extends Error {
4456
+ readonly timeoutMs: number;
4457
+ constructor(timeoutMs: number);
4458
+ }
4459
+ /**
4460
+ * The service answered 2xx but the body did not match the contract's response
4461
+ * schema. This is a bug in the service or a contract version mismatch, never
4462
+ * retried: retrying an already-succeeded mutating call would risk a duplicate.
4463
+ */
4464
+ declare class MailResponseValidationError extends Error {
4465
+ readonly operationId: string;
4466
+ readonly issues: unknown;
4467
+ constructor(operationId: string, issues: unknown);
4468
+ }
4469
+
4470
+ /**
4471
+ * Runtime primitives: only `fetch`, `AbortController` and Web Crypto, so the SDK
4472
+ * runs unmodified in Node 18+ and on edge runtimes. Node 18 ships `fetch` and
4473
+ * `AbortController` globally but `globalThis.crypto` only from Node 19 without a
4474
+ * flag; `randomUUID()` throws a clear error rather than silently falling back to
4475
+ * a weaker source, which is why the README calls out Node 20+ as the floor we test.
4476
+ */
4477
+ /** A fresh idempotency key, reused across every retry of the same call. */
4478
+ declare function generateIdempotencyKey(): string;
4479
+
4480
+ export { type BaseClientOptions, type DashboardMailClient, type DashboardMailClientOptions, type DashboardUserContext, type ExecuteArgs, type ExportedFile, MailApiError, type MailClient, type MailClientOptions, MailNetworkError, MailResponseValidationError, MailTimeoutError, type PageItem, type PaginatableOperationId, type PaginateArgs, type RequestOpts, type ResponseMeta, createDashboardMailClient, createMailClient, dispositionFilename, generateIdempotencyKey };