migma 1.3.3 → 1.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -126,6 +126,7 @@ Every method returns `{ data, error }` instead of throwing. TypeScript narrows t
126
126
  ```typescript
127
127
  const { data, error } = await migma.contacts.create({
128
128
  email: 'john@example.com',
129
+ status: 'subscribed', // only for contacts with marketing consent
129
130
  projectId: 'proj_abc123',
130
131
  });
131
132
 
@@ -206,7 +207,7 @@ const { data: contact } = await migma.contacts.create({
206
207
  // List with filters
207
208
  const { data: contacts } = await migma.contacts.list({
208
209
  projectId: 'proj_abc123',
209
- status: 'active',
210
+ status: 'subscribed',
210
211
  tags: 'newsletter',
211
212
  limit: 50,
212
213
  });
@@ -219,6 +220,19 @@ const { data: result } = await migma.contacts.bulkImport({
219
220
  ],
220
221
  projectId: 'proj_abc123',
221
222
  });
223
+
224
+ // Batch delete by email (up to 1000; unmatched emails come back in notFound)
225
+ const { data: deletion } = await migma.contacts.bulkDeleteByEmail({
226
+ emails: ['a@example.com', 'b@example.com'],
227
+ projectId: 'proj_abc123',
228
+ });
229
+
230
+ // Safe retries: pass an Idempotency-Key so a retried write never duplicates.
231
+ // Same key + same body within 24h replays the original response.
232
+ await migma.contacts.create(
233
+ { email: 'jane@example.com', projectId: 'proj_abc123' },
234
+ { idempotencyKey: 'signup-jane@example.com-1779292800' },
235
+ );
222
236
  ```
223
237
 
224
238
  [Contacts API Reference](https://docs.migma.ai/api-reference/contacts/get-contact)
@@ -297,6 +311,123 @@ await migma.emails.edit('email_abc123', {
297
311
  });
298
312
  ```
299
313
 
314
+ ### Campaigns
315
+
316
+ Create a campaign from a generated email, send or schedule it, then read its
317
+ engagement stats and per-recipient logs.
318
+
319
+ ```typescript
320
+ // Create from a generated email
321
+ const { data: campaign } = await migma.campaigns.create({
322
+ projectId: 'proj_abc123',
323
+ name: 'Spring Launch',
324
+ conversationId: 'conv_abc123',
325
+ emailId: 'email_abc123',
326
+ subject: 'Spring is here',
327
+ from: 'hello@yourdomain.com',
328
+ fromName: 'Your Brand',
329
+ recipientType: 'audience',
330
+ recipientId: 'aud_abc123',
331
+ });
332
+
333
+ // Send now (idempotency key recommended — see below)
334
+ await migma.campaigns.send(campaign.id, {
335
+ idempotencyKey: `campaign-send-${campaign.id}`,
336
+ });
337
+
338
+ // Or schedule for later
339
+ await migma.campaigns.schedule(
340
+ campaign.id,
341
+ { scheduledAt: '2026-07-01T15:00:00Z', scheduledTimezone: 'America/New_York' },
342
+ { idempotencyKey: `campaign-send-${campaign.id}` },
343
+ );
344
+
345
+ // Aggregated engagement metrics (cached, may be slightly stale)
346
+ const { data: stats } = await migma.campaigns.stats(campaign.id);
347
+ console.log(stats?.openRate, stats?.clickRate, stats?.lastUpdated);
348
+
349
+ // Per-recipient logs, cursor-paginated and optionally filtered by status
350
+ const { data: logs } = await migma.campaigns.logs(campaign.id, {
351
+ status: 'opened',
352
+ limit: 50,
353
+ });
354
+ for (const row of logs?.emails ?? []) {
355
+ console.log(row.to_email, row.status, row.opened_at);
356
+ }
357
+ if (logs?.hasMore) {
358
+ await migma.campaigns.logs(campaign.id, { cursor: logs.nextCursor ?? undefined });
359
+ }
360
+ ```
361
+
362
+ Campaign stats are sourced from the email tracking worker and cached on the
363
+ campaign, so they can lag live activity. `botOpens`, `botClicks`, and `mppOpens`
364
+ reflect Apple Mail Privacy Protection and bot detection when that data is
365
+ available. Log rows come straight from the tracking store, so their field names
366
+ are `snake_case` (`to_email`, `opened_at`, `bounce_type`) unlike the rest of the
367
+ API.
368
+
369
+ [Campaigns Guide](https://docs.migma.ai/campaigns/overview)
370
+
371
+ ### Idempotency
372
+
373
+ Write methods accept an optional trailing `CallOptions` argument carrying an
374
+ `idempotencyKey`. The key is sent as the `Idempotency-Key` header (max 100
375
+ characters) and is scoped to your API key for 24 hours:
376
+
377
+ - **Same key + same body** within 24h replays the original response (the server
378
+ marks the replay with an `Idempotent-Replayed: true` header).
379
+ - **Same key + different body** returns `409 IDEMPOTENCY_CONFLICT`.
380
+ - `429` and `5xx` responses are never cached, so they stay safe to retry — and
381
+ the SDK reuses your key across its own automatic retries, so a retried call
382
+ never duplicates.
383
+
384
+ ```typescript
385
+ // Sending — key on the recipient + send time
386
+ await migma.sending.send(
387
+ {
388
+ recipientType: 'email',
389
+ recipientEmail: 'user@example.com',
390
+ from: 'hello@yourdomain.com',
391
+ fromName: 'Your Brand',
392
+ subject: 'Welcome!',
393
+ emailId: 'email_abc123',
394
+ },
395
+ { idempotencyKey: 'send-email_abc123-user@example.com-now' },
396
+ );
397
+
398
+ // Campaign send — one key per campaign send
399
+ await migma.campaigns.send('camp_abc123', {
400
+ idempotencyKey: 'campaign-send-camp_abc123',
401
+ });
402
+
403
+ // Email generation — key on project + the turn/prompt
404
+ await migma.emails.generate(
405
+ { projectId: 'proj_abc123', prompt: 'Welcome email' },
406
+ { idempotencyKey: 'email-gen-proj_abc123-welcome' },
407
+ );
408
+
409
+ // Contact add — key on the email
410
+ await migma.contacts.create(
411
+ { email: 'jane@example.com', projectId: 'proj_abc123' },
412
+ { idempotencyKey: 'contact-jane@example.com' },
413
+ );
414
+ ```
415
+
416
+ **Choose a deterministic key** so the same logical operation produces the same
417
+ key on every attempt:
418
+
419
+ - send: `send-<emailId>-<recipientId|to>-<scheduledAt|"now">`
420
+ - campaign send: `campaign-send-<campaignId>`
421
+ - email generate: `email-gen-<projectId>-<turnOrPromptHash>`
422
+ - contact add: `contact-<email>`
423
+
424
+ **Anti-patterns to avoid:**
425
+
426
+ - Don't generate the key with `uuid()` or `Date.now()` per call — a fresh key
427
+ every attempt defeats deduplication across retries and process restarts.
428
+ - Don't hash the request body to build the key — identical retries you *want*
429
+ deduplicated would each get a different key, and you lose the conflict signal.
430
+
300
431
  ### Email Validation
301
432
 
302
433
  Run preflight checks — compatibility, links, spelling, and deliverability.
@@ -374,6 +505,14 @@ const { data: avail } = await migma.domains.checkAvailability('mycompany');
374
505
  if (avail.available) {
375
506
  await migma.domains.createManaged({ prefix: 'mycompany' });
376
507
  }
508
+
509
+ // Provision a transactional stream (notify.example.com) to isolate
510
+ // transactional reputation from marketing, then publish the returned DNS records
511
+ await migma.domains.provisionStream({ rootDomain: 'example.com', stream: 'transactional' });
512
+
513
+ // Or provision both streams (send. marketing + notify. transactional) in one call
514
+ const { data } = await migma.domains.setup({ rootDomain: 'example.com' });
515
+ // data.marketing, data.transactional
377
516
  ```
378
517
 
379
518
  [Domains API Reference](https://docs.migma.ai/api-reference/domains/list-domains)
@@ -391,7 +530,19 @@ const { data: tag } = await migma.tags.create({
391
530
  // Segments
392
531
  const { data: segment } = await migma.segments.create({
393
532
  name: 'Active US Customers',
394
- filters: { status: 'subscribed', customFields: { country: ['US'] } },
533
+ filters: {
534
+ status: 'subscribed',
535
+ fields: [{ key: 'country', mode: 'is', values: ['US'] }],
536
+ activity: [{ action: 'opened', channel: 'email', mode: 'within', unit: 'days', amount: 30 }],
537
+ },
538
+ projectId: 'proj_abc123',
539
+ });
540
+
541
+ const { data: campaignSegment } = await migma.segments.create({
542
+ name: 'Campaign openers',
543
+ filters: {
544
+ activity: [{ action: 'opened', channel: 'email', mode: 'within', unit: 'days', amount: 14, campaignId: 'cmp_123' }],
545
+ },
395
546
  projectId: 'proj_abc123',
396
547
  });
397
548
 
@@ -456,11 +607,11 @@ await migma.images.updateLogos('proj_abc123', {
456
607
  | `migma.sending` | `send` `getBatchStatus` | [Sending](https://docs.migma.ai/api-reference/sending/send-email) |
457
608
  | `migma.projects` | `list` `get` `import` `getImportStatus` `retryImport` `fieldCatalog` `importAndWait` | [Projects](https://docs.migma.ai/api-reference/projects/list-projects) |
458
609
  | `migma.emails` | `generate` `getGenerationStatus` `generateAndWait` `sendTest` `get` `edit` | [Email Generation](https://docs.migma.ai/api-reference/email/generate-email-async) |
459
- | `migma.campaigns` | `list` `create` `get` `send` `schedule` `cancel` `archive` `unarchive` | [Campaigns](https://docs.migma.ai/campaigns/overview) |
610
+ | `migma.campaigns` | `list` `create` `get` `send` `schedule` `cancel` `stats` `logs` `archive` `unarchive` | [Campaigns](https://docs.migma.ai/campaigns/overview) |
460
611
  | `migma.validation` | `all` `compatibility` `links` `spelling` `deliverability` | [Validation](https://docs.migma.ai/api-reference/email-validation/run-all-validation-checks) |
461
612
  | `migma.previews` | `create` `get` `getStatus` `getDevice` `getSupportedDevices` `createAndWait` | [Previews](https://docs.migma.ai/api-reference/email-previews/create-email-preview) |
462
613
  | `migma.export` | `getFormats` `getStatus` `html` `mjml` `pdf` `klaviyo` `mailchimp` `hubspot` | [Export](https://docs.migma.ai/api-reference/export/list-export-formats) |
463
- | `migma.domains` | `create` `list` `get` `verify` `update` `remove` `checkAvailability` `listManaged` `createManaged` `removeManaged` | [Domains](https://docs.migma.ai/api-reference/domains/list-domains) |
614
+ | `migma.domains` | `create` `list` `get` `verify` `update` `remove` `checkAvailability` `listManaged` `createManaged` `removeManaged` `provisionStream` `setup` | [Domains](https://docs.migma.ai/api-reference/domains/list-domains) |
464
615
  | `migma.webhooks` | `create` `list` `get` `update` `remove` `test` `getDeliveries` `getEvents` `getStats` | [Webhooks](https://docs.migma.ai/webhooks) |
465
616
  | `migma.knowledgeBase` | `list` `add` `update` `remove` | [API Ref](https://docs.migma.ai/api-reference/introduction) |
466
617
  | `migma.images` | `add` `update` `remove` `updateLogos` | [API Ref](https://docs.migma.ai/api-reference/introduction) |
package/dist/index.d.mts CHANGED
@@ -60,6 +60,16 @@ interface RequestOptions {
60
60
  path: string;
61
61
  body?: Record<string, unknown>;
62
62
  query?: Record<string, string | number | boolean | undefined>;
63
+ headers?: Record<string, string>;
64
+ }
65
+ /** Per-call options for write methods (POST/PATCH/DELETE). */
66
+ interface CallOptions {
67
+ /**
68
+ * Optional Idempotency-Key (max 100 chars). Same key + same body within 24h
69
+ * replays the original response; a different body returns 409 IDEMPOTENCY_CONFLICT.
70
+ * Reused across the SDK's own automatic retries so a retried call never duplicates.
71
+ */
72
+ idempotencyKey?: string;
63
73
  }
64
74
  declare class MigmaClient {
65
75
  private readonly apiKey;
@@ -80,16 +90,17 @@ declare class MigmaClient {
80
90
  data: T;
81
91
  count: number;
82
92
  }>>;
83
- post<T>(path: string, body?: Record<string, unknown>): Promise<MigmaResult<T>>;
84
- patch<T>(path: string, body?: Record<string, unknown>): Promise<MigmaResult<T>>;
93
+ post<T>(path: string, body?: Record<string, unknown>, options?: CallOptions): Promise<MigmaResult<T>>;
94
+ patch<T>(path: string, body?: Record<string, unknown>, options?: CallOptions): Promise<MigmaResult<T>>;
85
95
  put<T>(path: string, body?: Record<string, unknown>): Promise<MigmaResult<T>>;
86
- delete<T>(path: string, query?: Record<string, string | number | boolean | undefined>): Promise<MigmaResult<T>>;
96
+ delete<T>(path: string, query?: Record<string, string | number | boolean | undefined>, options?: CallOptions): Promise<MigmaResult<T>>;
97
+ private callHeaders;
87
98
  private buildUrl;
88
99
  private parseRetryAfter;
89
100
  private sleep;
90
101
  }
91
102
 
92
- type ContactStatus = 'active' | 'unsubscribed' | 'bounced' | 'complained';
103
+ type ContactStatus = 'subscribed' | 'unsubscribed' | 'bounced' | 'non-subscribed';
93
104
  interface Contact {
94
105
  id: string;
95
106
  email: string;
@@ -116,6 +127,7 @@ interface CreateContactParams {
116
127
  language?: string;
117
128
  tags?: string[];
118
129
  customFields?: Record<string, unknown>;
130
+ status?: ContactStatus;
119
131
  projectId: string;
120
132
  }
121
133
  interface UpdateContactParams {
@@ -150,6 +162,7 @@ interface BulkImportContactItem {
150
162
  language?: string;
151
163
  tags?: string[];
152
164
  customFields?: Record<string, unknown>;
165
+ status?: ContactStatus;
153
166
  }
154
167
  interface BulkImportParams {
155
168
  subscribers: BulkImportContactItem[];
@@ -178,6 +191,17 @@ interface BulkImportJobStatus {
178
191
  createdAt: string;
179
192
  completedAt: string | null;
180
193
  }
194
+ interface BatchDeleteContactsParams {
195
+ /** Email addresses to delete (1-1000 per request). */
196
+ emails: string[];
197
+ projectId: string;
198
+ }
199
+ interface BatchDeleteResponse {
200
+ /** Number of contacts actually deleted. */
201
+ deleted: number;
202
+ /** Submitted emails with no matching contact (not an error). */
203
+ notFound: string[];
204
+ }
181
205
  interface ChangeStatusParams {
182
206
  email: string;
183
207
  status: 'subscribed' | 'unsubscribed' | 'bounced' | 'non-subscribed';
@@ -189,14 +213,16 @@ interface ChangeStatusParams {
189
213
  declare class Contacts {
190
214
  private readonly client;
191
215
  constructor(client: MigmaClient);
192
- create(params: CreateContactParams): Promise<MigmaResult<Contact>>;
216
+ create(params: CreateContactParams, options?: CallOptions): Promise<MigmaResult<Contact>>;
193
217
  list(params: ListContactsParams): Promise<MigmaResult<ListContactsResponse>>;
194
218
  get(id: string, projectId: string): Promise<MigmaResult<Contact>>;
195
- update(id: string, params: UpdateContactParams): Promise<MigmaResult<Contact>>;
196
- remove(id: string, projectId: string): Promise<MigmaResult<DeleteResponse>>;
197
- bulkImport(params: BulkImportParams): Promise<MigmaResult<BulkImportResponse>>;
219
+ update(id: string, params: UpdateContactParams, options?: CallOptions): Promise<MigmaResult<Contact>>;
220
+ remove(id: string, projectId: string, options?: CallOptions): Promise<MigmaResult<DeleteResponse>>;
221
+ bulkImport(params: BulkImportParams, options?: CallOptions): Promise<MigmaResult<BulkImportResponse>>;
198
222
  getBulkImportStatus(jobId: string): Promise<MigmaResult<BulkImportJobStatus>>;
199
- changeStatus(params: ChangeStatusParams): Promise<MigmaResult<{
223
+ /** Batch delete contacts by email (up to 1000). Emails with no match come back in `notFound`. */
224
+ bulkDeleteByEmail(params: BatchDeleteContactsParams, options?: CallOptions): Promise<MigmaResult<BatchDeleteResponse>>;
225
+ changeStatus(params: ChangeStatusParams, options?: CallOptions): Promise<MigmaResult<{
200
226
  success: boolean;
201
227
  }>>;
202
228
  }
@@ -248,11 +274,15 @@ declare class Tags {
248
274
 
249
275
  interface SegmentFieldFilter {
250
276
  key: string;
251
- mode?: 'is' | 'is_not';
277
+ /** Exact match (is/is_not) or pattern match (starts_with/ends_with/contains/not_contains,
278
+ * compiled to anchored case-insensitive regex). Pattern modes keep a value group
279
+ * like "email ends_with .vc" accurate as new contacts arrive. */
280
+ mode?: 'is' | 'is_not' | 'starts_with' | 'ends_with' | 'contains' | 'not_contains';
252
281
  values: string[];
253
282
  }
254
283
  interface SegmentActivityFilter {
255
284
  action: 'sent' | 'opened' | 'clicked';
285
+ channel?: 'email';
256
286
  mode: 'within' | 'before' | 'never' | 'between';
257
287
  unit?: 'hours' | 'days';
258
288
  amount?: number;
@@ -430,7 +460,7 @@ interface BatchStatus {
430
460
  declare class Sending {
431
461
  private readonly client;
432
462
  constructor(client: MigmaClient);
433
- send(params: SendEmailParams): Promise<MigmaResult<SendEmailResponse>>;
463
+ send(params: SendEmailParams, options?: CallOptions): Promise<MigmaResult<SendEmailResponse>>;
434
464
  getBatchStatus(batchId: string): Promise<MigmaResult<BatchStatus>>;
435
465
  }
436
466
 
@@ -684,7 +714,7 @@ declare class Emails {
684
714
  /** List emails for a project */
685
715
  list(params: ListEmailsParams): Promise<MigmaResult<ListEmailsResponse>>;
686
716
  /** Start async email generation */
687
- generate(params: GenerateEmailParams): Promise<MigmaResult<GenerateEmailResponse>>;
717
+ generate(params: GenerateEmailParams, options?: CallOptions): Promise<MigmaResult<GenerateEmailResponse>>;
688
718
  /** Check email generation status */
689
719
  getGenerationStatus(conversationId: string): Promise<MigmaResult<EmailGenerationStatus>>;
690
720
  /** Fetch one generated email by email id */
@@ -695,7 +725,7 @@ declare class Emails {
695
725
  * Generate an email and wait for completion.
696
726
  * Polls getGenerationStatus until status is 'completed' or 'failed'.
697
727
  */
698
- generateAndWait(params: GenerateEmailParams, options?: PollingOptions): Promise<MigmaResult<EmailGenerationStatus>>;
728
+ generateAndWait(params: GenerateEmailParams, options?: PollingOptions, callOptions?: CallOptions): Promise<MigmaResult<EmailGenerationStatus>>;
699
729
  /** Send a test email from a completed conversation */
700
730
  sendTest(params: SendTestEmailParams): Promise<MigmaResult<SendTestEmailResponse>>;
701
731
  }
@@ -1011,6 +1041,34 @@ interface CreateManagedDomainParams {
1011
1041
  prefix: string;
1012
1042
  region?: string;
1013
1043
  }
1044
+ type DomainStream = 'transactional' | 'marketing';
1045
+ interface ProvisionStreamParams {
1046
+ /** Apex domain you own, e.g. 'acme.com'. */
1047
+ rootDomain: string;
1048
+ /** 'transactional' provisions notify.<rootDomain>; 'marketing' provisions send.<rootDomain>. */
1049
+ stream: DomainStream;
1050
+ region?: 'us-east-1' | 'eu-west-1';
1051
+ /** Show the apex domain in the From header when its DMARC passes. */
1052
+ vanityRootFrom?: boolean;
1053
+ }
1054
+ interface SetupDomainParams {
1055
+ /** Apex domain you own, e.g. 'acme.com'. */
1056
+ rootDomain: string;
1057
+ region?: 'us-east-1' | 'eu-west-1';
1058
+ /** Default From display name applied to both provisioned streams. */
1059
+ fromName?: string;
1060
+ /** Associate the provisioned streams with a project. */
1061
+ projectId?: string;
1062
+ /** Show the apex domain in the From header when its DMARC passes. Defaults to true. */
1063
+ vanityRootFrom?: boolean;
1064
+ }
1065
+ /** Both stream identities provisioned for a root domain by `domains.setup`. */
1066
+ interface SetupDomainResponse {
1067
+ /** send.<rootDomain> marketing stream identity. */
1068
+ marketing: Domain;
1069
+ /** notify.<rootDomain> transactional stream identity. */
1070
+ transactional: Domain;
1071
+ }
1014
1072
  interface DomainDeleteResponse {
1015
1073
  domain: string;
1016
1074
  deleted: boolean;
@@ -1029,6 +1087,18 @@ declare class Domains {
1029
1087
  listManaged(): Promise<MigmaResult<Domain[]>>;
1030
1088
  createManaged(params: CreateManagedDomainParams): Promise<MigmaResult<Domain>>;
1031
1089
  removeManaged(domain: string): Promise<MigmaResult<DomainDeleteResponse>>;
1090
+ /**
1091
+ * Provision a transactional or marketing stream identity on a domain you own.
1092
+ * Creates notify.<rootDomain> (transactional) or send.<rootDomain> (marketing)
1093
+ * to isolate transactional reputation from marketing. Returns DNS records to publish.
1094
+ */
1095
+ provisionStream(params: ProvisionStreamParams): Promise<MigmaResult<Domain>>;
1096
+ /**
1097
+ * Provision BOTH stream identities for a domain you own in one call:
1098
+ * send.<rootDomain> (marketing) and notify.<rootDomain> (transactional).
1099
+ * Idempotent. Returns both domains with DNS records to publish.
1100
+ */
1101
+ setup(params: SetupDomainParams): Promise<MigmaResult<SetupDomainResponse>>;
1032
1102
  }
1033
1103
 
1034
1104
  type WebhookEventType = 'email.generation.started' | 'email.generation.completed' | 'email.generation.failed' | 'email.test.sent' | 'project.import.started' | 'project.import.processing' | 'project.import.completed' | 'project.import.failed' | 'export.completed' | 'export.failed' | 'subscriber.added' | 'subscriber.updated' | 'subscriber.unsubscribed' | 'subscriber.bulk_imported' | 'api_key.created' | 'api_key.revoked';
@@ -1050,10 +1120,19 @@ interface Webhook {
1050
1120
  url: string;
1051
1121
  events: WebhookEventType[];
1052
1122
  active: boolean;
1053
- secret: string;
1123
+ /** Whether a signing secret is configured. Returned by create and get. */
1124
+ secretConfigured?: boolean;
1054
1125
  description?: string;
1055
1126
  createdAt: string;
1056
1127
  }
1128
+ interface CreateWebhookResponse extends Webhook {
1129
+ /**
1130
+ * The signing secret, returned ONCE at creation. Store it now — GET and list
1131
+ * never return it. To rotate, delete and recreate the webhook.
1132
+ */
1133
+ secret: string;
1134
+ secretConfigured: boolean;
1135
+ }
1057
1136
  interface WebhookDetail extends Webhook {
1058
1137
  customHeaders?: Record<string, string>;
1059
1138
  successCount: number;
@@ -1098,7 +1177,7 @@ declare class Webhooks {
1098
1177
  private readonly client;
1099
1178
  constructor(client: MigmaClient);
1100
1179
  list(): Promise<MigmaResult<ListWebhooksResponse>>;
1101
- create(params: CreateWebhookParams): Promise<MigmaResult<Webhook>>;
1180
+ create(params: CreateWebhookParams): Promise<MigmaResult<CreateWebhookResponse>>;
1102
1181
  get(webhookId: string): Promise<MigmaResult<WebhookDetail>>;
1103
1182
  update(webhookId: string, params: UpdateWebhookParams): Promise<MigmaResult<{
1104
1183
  updated: boolean;
@@ -1241,16 +1320,84 @@ interface ScheduleCampaignParams {
1241
1320
  scheduledAt: string;
1242
1321
  scheduledTimezone?: string;
1243
1322
  }
1323
+ /**
1324
+ * Aggregated engagement metrics for a campaign.
1325
+ *
1326
+ * Sourced from the email tracking worker and cached on the campaign, so values
1327
+ * may be slightly stale. `botOpens`, `botClicks`, and `mppOpens` are present
1328
+ * when Apple Mail Privacy Protection / bot detection data is available.
1329
+ */
1330
+ interface CampaignStats {
1331
+ totalSent: number;
1332
+ totalDelivered: number;
1333
+ uniqueOpens: number;
1334
+ totalOpens: number;
1335
+ uniqueClicks: number;
1336
+ totalClicks: number;
1337
+ unsubscribes: number;
1338
+ bounces: number;
1339
+ /** 0-100 */
1340
+ openRate: number;
1341
+ /** 0-100 */
1342
+ clickRate: number;
1343
+ /** ISO 8601 timestamp of when these stats were last refreshed. */
1344
+ lastUpdated: string;
1345
+ botOpens?: number;
1346
+ botClicks?: number;
1347
+ mppOpens?: number;
1348
+ }
1349
+ /**
1350
+ * A single per-recipient email log row for a campaign. Returned directly from
1351
+ * the tracking worker's D1 `emails` table, so the field names are snake_case
1352
+ * (unlike the rest of the API).
1353
+ */
1354
+ interface CampaignLog {
1355
+ id: number;
1356
+ tracking_id: string;
1357
+ user_id: string;
1358
+ domain: string;
1359
+ from_email: string;
1360
+ to_email: string;
1361
+ subscriber_id: string | null;
1362
+ subject: string | null;
1363
+ /** Delivery status, e.g. 'sent', 'delivered', 'bounced', 'suppressed'. */
1364
+ status: string;
1365
+ opened_at: string | null;
1366
+ clicked_at: string | null;
1367
+ open_count: number;
1368
+ click_count: number;
1369
+ bounce_type: string | null;
1370
+ complaint_type: string | null;
1371
+ suppression_type: string | null;
1372
+ suppression_reason: string | null;
1373
+ conversation_id: string | null;
1374
+ campaign_id: string | null;
1375
+ created_at: string;
1376
+ }
1377
+ interface CampaignLogsParams {
1378
+ limit?: number;
1379
+ cursor?: string;
1380
+ status?: 'delivered' | 'opened' | 'clicked' | 'bounced' | 'spam_report';
1381
+ }
1382
+ interface CampaignLogsResponse {
1383
+ emails: CampaignLog[];
1384
+ nextCursor: string | null;
1385
+ hasMore: boolean;
1386
+ }
1244
1387
 
1245
1388
  declare class Campaigns {
1246
1389
  private readonly client;
1247
1390
  constructor(client: MigmaClient);
1248
1391
  list(params: ListCampaignsParams): Promise<MigmaResult<ListCampaignsResponse>>;
1249
- create(params: CreateCampaignParams): Promise<MigmaResult<Campaign>>;
1392
+ create(params: CreateCampaignParams, options?: CallOptions): Promise<MigmaResult<Campaign>>;
1250
1393
  get(id: string): Promise<MigmaResult<Campaign>>;
1251
- send(id: string): Promise<MigmaResult<Campaign>>;
1252
- schedule(id: string, params: ScheduleCampaignParams): Promise<MigmaResult<Campaign>>;
1253
- cancel(id: string): Promise<MigmaResult<Campaign>>;
1394
+ send(id: string, options?: CallOptions): Promise<MigmaResult<Campaign>>;
1395
+ schedule(id: string, params: ScheduleCampaignParams, options?: CallOptions): Promise<MigmaResult<Campaign>>;
1396
+ cancel(id: string, options?: CallOptions): Promise<MigmaResult<Campaign>>;
1397
+ /** Aggregated engagement metrics for a campaign (cached, may be slightly stale). */
1398
+ stats(id: string): Promise<MigmaResult<CampaignStats>>;
1399
+ /** Per-recipient email logs for a campaign (cursor-paginated). */
1400
+ logs(id: string, params?: CampaignLogsParams): Promise<MigmaResult<CampaignLogsResponse>>;
1254
1401
  archive(id: string): Promise<MigmaResult<Campaign>>;
1255
1402
  unarchive(id: string): Promise<MigmaResult<Campaign>>;
1256
1403
  }
@@ -1283,4 +1430,4 @@ declare class Migma {
1283
1430
  constructor(apiKey: string, config?: MigmaConfig);
1284
1431
  }
1285
1432
 
1286
- export { type AddImageParams, type AddKnowledgeBaseParams, type AnalyzeDeliverabilityParams, type AnalyzeLinksParams, type ApiResponse, type BatchStatus, type BulkImportAsyncResponse, type BulkImportContactItem, type BulkImportJobStatus, type BulkImportParams, type BulkImportResponse, type BulkImportSyncResponse, type Campaign, type CampaignStatus, type ChangeStatusParams, type CheckCompatibilityParams, type CheckSpellingParams, type CheckedLink, type ClientConfig, type CompatibilityResponse, type Contact, type ContactStatus, type CreateCampaignParams, type CreateContactParams, type CreateDomainParams, type CreateManagedDomainParams, type CreatePreviewParams, type CreatePreviewResponse, type CreateSegmentParams, type CreateTagParams, type CreateTopicParams, type CreateWebhookParams, type DeleteResponse, type DeliverabilityResponse, type DeviceCategoriesResponse, type DnsRecord, type Domain, type DomainAvailability, type DomainDeleteResponse, type DomainVerificationResult, type EditEmailParams, type Email, type EmailGenerationResult, type EmailGenerationStatus, type EmailImage, type ExportFile, type ExportFormat, type ExportFormatsResponse, type ExportResult, type ExportStatusResponse, type FieldCatalogEntry, type FieldCatalogEntryType, type FieldCatalogParams, type FieldCatalogResponse, type GenerateEmailParams, type GenerateEmailResponse, type GeneratedEmail, type GetDevicePreviewResponse, type GetPreviewResponse, type GetPreviewStatusResponse, type GetSupportedDevicesResponse, type HubspotExportParams, type ImportProjectParams, type ImportProjectResponse, type ImportStatusResponse, type KnowledgeBaseEntry, type KnowledgeBaseListResponse, type LinkAnalysisResponse, type ListCampaignsParams, type ListCampaignsResponse, type ListContactsParams, type ListContactsResponse, type ListEmailsEmail, type ListEmailsParams, type ListEmailsResponse, type ListProjectsParams, type ListProjectsResponse, type ListSegmentsResponse, type ListTagsParams, type ListTagsResponse, type ListTopicsParams, type ListTopicsResponse, type ListWebhooksResponse, type LogosResponse, type MessageResponse, Migma, MigmaClient, type MigmaConfig, MigmaError, MigmaErrorCode, type MigmaResult, type PollingOptions, type PreviewDevice, type PreviewDeviceCategory, type PreviewDeviceStatus, type PreviewMetadata, type PreviewStatus, type Project, type ProjectImage, type ProviderType, type RecipientType, type RetryImportResponse, type ScheduleCampaignParams, type Segment, type SegmentActivityFilter, type SegmentFieldFilter, type SegmentFilters, type SendEmailParams, type SendEmailResponse, type SendTestEmailParams, type SendTestEmailResponse, type SpellingResponse, type SupportedDevice, type Tag, type Topic, type TopicSubscriptionParams, type TopicSubscriptionResponse, type UpdateContactParams, type UpdateDomainParams, type UpdateImageParams, type UpdateKnowledgeBaseParams, type UpdateLogosParams, type UpdateSegmentParams, type UpdateTagParams, type UpdateTopicParams, type UpdateWebhookParams, type ValidateAllParams, type ValidateAllResponse, type Webhook, type WebhookDeliveriesResponse, type WebhookDelivery, type WebhookDetail, type WebhookEvent, type WebhookEventType, type WebhookEventsResponse, type WebhookTestResult, poll };
1433
+ export { type AddImageParams, type AddKnowledgeBaseParams, type AnalyzeDeliverabilityParams, type AnalyzeLinksParams, type ApiResponse, type BatchDeleteContactsParams, type BatchDeleteResponse, type BatchStatus, type BulkImportAsyncResponse, type BulkImportContactItem, type BulkImportJobStatus, type BulkImportParams, type BulkImportResponse, type BulkImportSyncResponse, type Campaign, type CampaignLog, type CampaignLogsParams, type CampaignLogsResponse, type CampaignStats, type CampaignStatus, type ChangeStatusParams, type CheckCompatibilityParams, type CheckSpellingParams, type CheckedLink, type ClientConfig, type CompatibilityResponse, type Contact, type ContactStatus, type CreateCampaignParams, type CreateContactParams, type CreateDomainParams, type CreateManagedDomainParams, type CreatePreviewParams, type CreatePreviewResponse, type CreateSegmentParams, type CreateTagParams, type CreateTopicParams, type CreateWebhookParams, type CreateWebhookResponse, type DeleteResponse, type DeliverabilityResponse, type DeviceCategoriesResponse, type DnsRecord, type Domain, type DomainAvailability, type DomainDeleteResponse, type DomainStream, type DomainVerificationResult, type EditEmailParams, type Email, type EmailGenerationResult, type EmailGenerationStatus, type EmailImage, type ExportFile, type ExportFormat, type ExportFormatsResponse, type ExportResult, type ExportStatusResponse, type FieldCatalogEntry, type FieldCatalogEntryType, type FieldCatalogParams, type FieldCatalogResponse, type GenerateEmailParams, type GenerateEmailResponse, type GeneratedEmail, type GetDevicePreviewResponse, type GetPreviewResponse, type GetPreviewStatusResponse, type GetSupportedDevicesResponse, type HubspotExportParams, type ImportProjectParams, type ImportProjectResponse, type ImportStatusResponse, type KnowledgeBaseEntry, type KnowledgeBaseListResponse, type LinkAnalysisResponse, type ListCampaignsParams, type ListCampaignsResponse, type ListContactsParams, type ListContactsResponse, type ListEmailsEmail, type ListEmailsParams, type ListEmailsResponse, type ListProjectsParams, type ListProjectsResponse, type ListSegmentsResponse, type ListTagsParams, type ListTagsResponse, type ListTopicsParams, type ListTopicsResponse, type ListWebhooksResponse, type LogosResponse, type MessageResponse, Migma, MigmaClient, type MigmaConfig, MigmaError, MigmaErrorCode, type MigmaResult, type PollingOptions, type PreviewDevice, type PreviewDeviceCategory, type PreviewDeviceStatus, type PreviewMetadata, type PreviewStatus, type Project, type ProjectImage, type ProviderType, type ProvisionStreamParams, type RecipientType, type RetryImportResponse, type ScheduleCampaignParams, type Segment, type SegmentActivityFilter, type SegmentFieldFilter, type SegmentFilters, type SendEmailParams, type SendEmailResponse, type SendTestEmailParams, type SendTestEmailResponse, type SetupDomainParams, type SetupDomainResponse, type SpellingResponse, type SupportedDevice, type Tag, type Topic, type TopicSubscriptionParams, type TopicSubscriptionResponse, type UpdateContactParams, type UpdateDomainParams, type UpdateImageParams, type UpdateKnowledgeBaseParams, type UpdateLogosParams, type UpdateSegmentParams, type UpdateTagParams, type UpdateTopicParams, type UpdateWebhookParams, type ValidateAllParams, type ValidateAllResponse, type Webhook, type WebhookDeliveriesResponse, type WebhookDelivery, type WebhookDetail, type WebhookEvent, type WebhookEventType, type WebhookEventsResponse, type WebhookTestResult, poll };