@messagebird/sdk 0.1.1

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,1692 @@
1
+ /** Transport metadata exposed to callers via `.withResponse()`. */
2
+ interface BirdResponse {
3
+ status: number;
4
+ headers: Headers;
5
+ /** Correlation ID — the `X-Request-Id` header. */
6
+ requestId: string;
7
+ }
8
+ /** Per-request lifecycle inputs, supplied by the resource method. */
9
+ interface RequestLifecycleOptions {
10
+ /** HTTP method — decides idempotency-key generation and retry safety. */
11
+ method: string;
12
+ /** Caller-supplied idempotency key; auto-generated for mutations if absent. */
13
+ idempotencyKey?: string;
14
+ /** Caller cancellation. */
15
+ signal?: AbortSignal;
16
+ /** Per-attempt timeout (ms). Overrides the client default. */
17
+ timeout?: number;
18
+ /** Max retry attempts. Overrides the client default. */
19
+ maxRetries?: number;
20
+ }
21
+ /** The shape a generated hey-api SDK call resolves to. */
22
+ interface FetchOutcome<T> {
23
+ data?: T;
24
+ error?: unknown;
25
+ /** Present whenever the HTTP round-trip completed; absent only on a rejected call. */
26
+ response?: Response;
27
+ }
28
+ /** Context handed to the call thunk on each attempt. */
29
+ interface AttemptContext {
30
+ signal: AbortSignal;
31
+ idempotencyKey?: string;
32
+ }
33
+ interface CoreDefaults {
34
+ /** Per-attempt timeout (ms). */
35
+ timeout: number;
36
+ /** Max retry attempts. */
37
+ maxRetries: number;
38
+ }
39
+ declare class BirdHTTPClient {
40
+ private readonly defaults;
41
+ constructor(defaults: CoreDefaults);
42
+ /**
43
+ * Run a generated hey-api SDK call through the request lifecycle.
44
+ *
45
+ * @param call Invokes the SDK function; receives the per-attempt signal and
46
+ * the idempotency key to set as a header.
47
+ * @returns the parsed body plus transport metadata.
48
+ * @throws a `BirdError` subclass on terminal failure; the native
49
+ * `AbortError` if the caller's signal aborts.
50
+ */
51
+ request<T>(call: (ctx: AttemptContext) => Promise<FetchOutcome<T>>, options: RequestLifecycleOptions): Promise<{
52
+ data: T;
53
+ response: BirdResponse;
54
+ }>;
55
+ }
56
+
57
+ /** Root of the hierarchy. Catch this to catch anything the SDK throws. */
58
+ declare class BirdError extends Error {
59
+ constructor(message: string);
60
+ }
61
+ /** Network-level failure with no HTTP response (DNS, refused, socket hangup). */
62
+ declare class BirdConnectionError extends BirdError {
63
+ constructor(message: string);
64
+ }
65
+ /** A single attempt exceeded its timeout. Retryable. */
66
+ declare class BirdTimeoutError extends BirdError {
67
+ readonly timeoutMs: number;
68
+ constructor(message: string, timeoutMs: number);
69
+ }
70
+ /** A webhook payload failed signature verification (bad signature, stale timestamp, malformed headers). */
71
+ declare class BirdWebhookVerificationError extends BirdError {
72
+ constructor(message: string);
73
+ }
74
+ /** One per-field validation failure (the `details` array on a 422). */
75
+ interface ErrorDetail {
76
+ /** Dotted field path, e.g. `to[0].email`, `subject`, `.`. */
77
+ param: string;
78
+ /** What is wrong with this field. */
79
+ message: string;
80
+ }
81
+ /** Constructor fields shared by every API error, mapped from the wire body. */
82
+ interface BirdAPIErrorFields {
83
+ statusCode: number;
84
+ /** Opaque, stable error code (`E#####`). */
85
+ code: string;
86
+ /** Coarse category — the value callers branch on. */
87
+ type: string;
88
+ /** Human-readable slug for logs. Paired with `code`, never replaces it. */
89
+ errorName: string;
90
+ message: string;
91
+ /** Stable link to the docs page for this code. */
92
+ docUrl: string;
93
+ /** Correlation ID — also the `X-Request-Id` response header. */
94
+ requestId: string;
95
+ /** Offending field, when applicable. */
96
+ param?: string;
97
+ /** Verbatim code from a downstream system (SMTP reply, payment decline). */
98
+ vendorCode?: string;
99
+ }
100
+ /** The server returned an error body. Base for every `type`-specific class. */
101
+ declare class BirdAPIError extends BirdError {
102
+ readonly statusCode: number;
103
+ readonly code: string;
104
+ readonly type: string;
105
+ readonly errorName: string;
106
+ readonly docUrl: string;
107
+ readonly requestId: string;
108
+ readonly param?: string;
109
+ readonly vendorCode?: string;
110
+ constructor(fields: BirdAPIErrorFields);
111
+ }
112
+ /** 401 — authentication failed or missing. */
113
+ declare class BirdAuthError extends BirdAPIError {
114
+ constructor(fields: BirdAPIErrorFields);
115
+ }
116
+ /** 403 — authenticated but not allowed. */
117
+ declare class BirdPermissionError extends BirdAPIError {
118
+ constructor(fields: BirdAPIErrorFields);
119
+ }
120
+ /** 404 — resource does not exist. */
121
+ declare class BirdNotFoundError extends BirdAPIError {
122
+ constructor(fields: BirdAPIErrorFields);
123
+ }
124
+ /** 409 — semantic conflict (e.g. a unique value already taken). */
125
+ declare class BirdConflictError extends BirdAPIError {
126
+ constructor(fields: BirdAPIErrorFields);
127
+ }
128
+ /** 400 — malformed request. */
129
+ declare class BirdBadRequestError extends BirdAPIError {
130
+ constructor(fields: BirdAPIErrorFields);
131
+ }
132
+ /** 402 — billing/balance problem. */
133
+ declare class BirdBillingError extends BirdAPIError {
134
+ constructor(fields: BirdAPIErrorFields);
135
+ }
136
+ /** 412/428 — a precondition was not met. */
137
+ declare class BirdPreconditionError extends BirdAPIError {
138
+ constructor(fields: BirdAPIErrorFields);
139
+ }
140
+ /** 413 — request body too large. */
141
+ declare class BirdPayloadTooLargeError extends BirdAPIError {
142
+ constructor(fields: BirdAPIErrorFields);
143
+ }
144
+ /** 500 — unexpected server error. */
145
+ declare class BirdInternalError extends BirdAPIError {
146
+ constructor(fields: BirdAPIErrorFields);
147
+ }
148
+ /** 501 — endpoint not implemented. */
149
+ declare class BirdNotImplementedError extends BirdAPIError {
150
+ constructor(fields: BirdAPIErrorFields);
151
+ }
152
+ /** 421 — request reached the wrong region (ADR-0036). */
153
+ declare class BirdMisdirectedError extends BirdAPIError {
154
+ constructor(fields: BirdAPIErrorFields);
155
+ }
156
+ /** 503 — service temporarily unavailable. */
157
+ declare class BirdServiceUnavailableError extends BirdAPIError {
158
+ constructor(fields: BirdAPIErrorFields);
159
+ }
160
+ /** 422 — field validation failed; `details` carries the per-field errors. */
161
+ declare class BirdValidationError extends BirdAPIError {
162
+ readonly details: ErrorDetail[];
163
+ constructor(fields: BirdAPIErrorFields & {
164
+ details: ErrorDetail[];
165
+ });
166
+ }
167
+ /** 429 — rate limited; `retryAfter` is the server-advised wait in seconds. */
168
+ declare class BirdRateLimitError extends BirdAPIError {
169
+ readonly retryAfter?: number;
170
+ constructor(fields: BirdAPIErrorFields & {
171
+ retryAfter?: number;
172
+ });
173
+ }
174
+
175
+ /** Per-request overrides accepted by every resource method. */
176
+ interface RequestOptions$1 {
177
+ /** Idempotency key; auto-generated for mutations if omitted, reused on retry. */
178
+ idempotencyKey?: string;
179
+ /** Caller cancellation. Rejects with the native `AbortError`. */
180
+ signal?: AbortSignal;
181
+ /** Per-attempt timeout (ms). Overrides the client default. */
182
+ timeout?: number;
183
+ /** Max retry attempts. Overrides the client default. */
184
+ maxRetries?: number;
185
+ /** Extra headers for this request. SDK-internal headers win on conflict. */
186
+ headers?: Record<string, string>;
187
+ }
188
+ /**
189
+ * The result of `.safe()` — the value or the error, never thrown. On success
190
+ * `data` and the `response` envelope are present and `error` is `null`. On
191
+ * failure `error` is a `BirdError` you can `instanceof`-narrow, and `data`/
192
+ * `response` are `null` — the metadata you need (status, request id) is on the
193
+ * error itself. A caller-initiated abort is not a Bird failure and still throws
194
+ * (the native `AbortError`, ADR-0042 §1).
195
+ */
196
+ type SafeResult<T> = {
197
+ data: T;
198
+ error: null;
199
+ response: BirdResponse;
200
+ } | {
201
+ data: null;
202
+ error: BirdError;
203
+ response: null;
204
+ };
205
+ /** Single-result return: `await` for the value, `.withResponse()` for metadata. */
206
+ interface APIPromise<T> extends Promise<T> {
207
+ withResponse(): Promise<{
208
+ data: T;
209
+ response: BirdResponse;
210
+ }>;
211
+ /** Resolve to `{ data, error }` instead of throwing. */
212
+ safe(): Promise<SafeResult<T>>;
213
+ }
214
+ /** One cursor-paginated page — the wire envelope shape (snake), verbatim. */
215
+ interface CursorPage<T> {
216
+ data: T[];
217
+ /** Pass back as `starting_after` to advance. Null at the end. */
218
+ next_cursor: string | null;
219
+ /** Pass back as `ending_before` to step back. Null at the start. */
220
+ prev_cursor: string | null;
221
+ /** Refresh anchor; pass as `ending_before` later for items since this page. */
222
+ refresh_cursor: string | null;
223
+ /** Total across all pages — only when `include_total=true` was passed. */
224
+ total?: number | null;
225
+ }
226
+ /**
227
+ * List return (R1): `await` resolves the first page; `for await` walks every
228
+ * item across all pages, fetching subsequent pages lazily.
229
+ */
230
+ interface PaginatedPromise<T> extends Promise<CursorPage<T>>, AsyncIterable<T> {
231
+ withResponse(): Promise<{
232
+ data: CursorPage<T>;
233
+ response: BirdResponse;
234
+ }>;
235
+ /** Resolve the first page as `{ data, error }` instead of throwing. */
236
+ safe(): Promise<SafeResult<CursorPage<T>>>;
237
+ }
238
+
239
+ /**
240
+ * An email address was added to the workspace's suppression list (manually, via complaint, or via hard bounce). Payload schema not yet finalized.
241
+ */
242
+ type EventEmailSuppressionCreated = {
243
+ /**
244
+ * Event type.
245
+ */
246
+ type: "email_suppression.created";
247
+ /**
248
+ * When the event occurred.
249
+ */
250
+ timestamp: string;
251
+ /**
252
+ * Event payload. The fields for this event are not yet finalized.
253
+ */
254
+ data: {
255
+ [key: string]: never;
256
+ };
257
+ };
258
+ /**
259
+ * Payload of the email.unsubscribed event.
260
+ */
261
+ type EventEmailUnsubscribedData = EventEmailBase;
262
+ /**
263
+ * Structured key/value tag attached to an email send. Surfaces in list filters, the event log, and webhook payloads. Use tags for low-cardinality filtering dimensions (category, experiment ID, template ID). For arbitrary per-send context that does not need to be filterable, use `metadata`.
264
+ * Tag count and per-tag size are capped to keep per-send tag payloads small — see EmailMessageSendRequest for the array maximum.
265
+ *
266
+ */
267
+ type EmailTag = {
268
+ /**
269
+ * Tag name. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 32 characters.
270
+ *
271
+ */
272
+ name: string;
273
+ /**
274
+ * Tag value. ASCII letters, digits, underscore, and hyphen only. Case-sensitive. Maximum 64 characters.
275
+ *
276
+ */
277
+ value: string;
278
+ };
279
+ /**
280
+ * Envelope position of a recipient on an outbound email event.
281
+ */
282
+ type RecipientRole = "to" | "cc" | "bcc";
283
+ type WorkspaceId = string;
284
+ type RecipientId = string;
285
+ type EmailId = string;
286
+ /**
287
+ * Identity fields shared by every email lifecycle event payload.
288
+ */
289
+ type EventEmailBase = {
290
+ /**
291
+ * ID of the email send.
292
+ */
293
+ email_id: EmailId;
294
+ /**
295
+ * ID of the recipient.
296
+ */
297
+ recipient_id: RecipientId;
298
+ /**
299
+ * ID of the workspace.
300
+ */
301
+ workspace_id: WorkspaceId;
302
+ /**
303
+ * Recipient address as it appeared on the envelope.
304
+ */
305
+ recipient: string;
306
+ /**
307
+ * Envelope position of the recipient.
308
+ */
309
+ recipient_role: RecipientRole;
310
+ /**
311
+ * Tags provided on the send request, echoed on every event for the send so you can route and correlate without an extra lookup. Null when the send carried no tags.
312
+ *
313
+ */
314
+ tags: Array<EmailTag> | null;
315
+ /**
316
+ * The metadata object provided on the send request, echoed on every event for the send so you can correlate events with your own records. Null when the send carried no metadata.
317
+ *
318
+ */
319
+ metadata: {
320
+ [key: string]: unknown;
321
+ } | null;
322
+ };
323
+ /**
324
+ * Recipient unsubscribed by clicking a tracked unsubscribe link in the email. Fires once per recipient.
325
+ */
326
+ type EventEmailUnsubscribed = {
327
+ /**
328
+ * Event type.
329
+ */
330
+ type: "email.unsubscribed";
331
+ /**
332
+ * Time the unsubscribe was recorded.
333
+ */
334
+ timestamp: string;
335
+ data: EventEmailUnsubscribedData;
336
+ };
337
+ /**
338
+ * Why an email was rejected before delivery.
339
+ * `recipient_suppressed` means the recipient is on the workspace suppression list, so Bird did not attempt delivery. `transmission_failed` means the message could not be transmitted for delivery. `generation_failure` means the message could not be built for delivery (a template or content issue). `policy_rejection` means the message was refused by sending policy.
340
+ *
341
+ */
342
+ type EmailRejectionReason = "recipient_suppressed" | "transmission_failed" | "generation_failure" | "policy_rejection";
343
+ /**
344
+ * Payload of the email.rejected event.
345
+ */
346
+ type EventEmailRejectedData = EventEmailBase & {
347
+ rejection_reason: EmailRejectionReason;
348
+ };
349
+ /**
350
+ * Bird rejected the email before sending it (suppression list hit, transmission failure, or a content/policy guard). Fires once per recipient.
351
+ */
352
+ type EventEmailRejected = {
353
+ /**
354
+ * Event type.
355
+ */
356
+ type: "email.rejected";
357
+ /**
358
+ * Time the rejection was recorded.
359
+ */
360
+ timestamp: string;
361
+ data: EventEmailRejectedData;
362
+ };
363
+ /**
364
+ * Payload of the email.received event.
365
+ */
366
+ type EventEmailReceivedData = {
367
+ /**
368
+ * ID of the received email (rem_ prefix). Use it with GET /v1/email/inbound-messages/{id} to fetch the body.
369
+ */
370
+ inbound_message_id: string;
371
+ /**
372
+ * ID of the workspace.
373
+ */
374
+ workspace_id: WorkspaceId;
375
+ /**
376
+ * RFC 5322 Message-ID header from the sender, or null when the sender did not include one.
377
+ */
378
+ message_id: string | null;
379
+ /**
380
+ * Envelope-from address.
381
+ */
382
+ from: string;
383
+ /**
384
+ * Subject line as received.
385
+ */
386
+ subject: string;
387
+ };
388
+ /**
389
+ * Bird received and parsed an inbound email. The payload includes message metadata, extracted text, and threading headers (not the raw body). Additional fields — cc/bcc recipients, attachment metadata, and authentication results — will be added in a future release.
390
+ */
391
+ type EventEmailReceived = {
392
+ /**
393
+ * Event type.
394
+ */
395
+ type: "email.received";
396
+ /**
397
+ * When Bird received the message.
398
+ */
399
+ timestamp: string;
400
+ data: EventEmailReceivedData;
401
+ };
402
+ /**
403
+ * Payload of the email.processed event.
404
+ */
405
+ type EventEmailProcessedData = EventEmailBase;
406
+ /**
407
+ * Bird processed the message and queued it for delivery to the recipient's mail server. Fires once per recipient when the message enters the SMTP delivery queue.
408
+ */
409
+ type EventEmailProcessed = {
410
+ /**
411
+ * Event type.
412
+ */
413
+ type: "email.processed";
414
+ /**
415
+ * Time Bird processed the message and queued it for SMTP delivery.
416
+ */
417
+ timestamp: string;
418
+ data: EventEmailProcessedData;
419
+ };
420
+ /**
421
+ * Payload of the email.out_of_band_bounce event.
422
+ */
423
+ type EventEmailOutOfBandBounceData = EventEmailBase & {
424
+ bounce_type: EmailBounceType;
425
+ /**
426
+ * Numeric bounce classification for fine-grained deliverability triage, or null when the receiving server's response could not be classified.
427
+ *
428
+ */
429
+ bounce_class: number | null;
430
+ /**
431
+ * SMTP reply code returned by the receiving mail server, or null when none was provided.
432
+ */
433
+ bounce_code: string | null;
434
+ /**
435
+ * Human-readable reason the receiving mail server gave for the bounce, or null when none was provided.
436
+ */
437
+ bounce_description: string | null;
438
+ /**
439
+ * The IP address used to send this message, or null when it is not known.
440
+ */
441
+ sending_ip: string | null;
442
+ };
443
+ /**
444
+ * Bounce classification. `hard` is a permanent failure (invalid address or non-existent domain). `soft` is a transient failure (mailbox full, server temporarily unavailable). `block` indicates the receiving mail server blocked the sending IP for reputation reasons. `admin` indicates an administrative refusal (relaying denied, blocklisted domain). `undetermined` is used when the receiving server's response is ambiguous.
445
+ *
446
+ */
447
+ type EmailBounceType = "hard" | "soft" | "undetermined" | "admin" | "block";
448
+ /**
449
+ * A bounce notification arrived after the message had already been accepted for delivery. Fires once per recipient.
450
+ */
451
+ type EventEmailOutOfBandBounce = {
452
+ /**
453
+ * Event type.
454
+ */
455
+ type: "email.out_of_band_bounce";
456
+ /**
457
+ * Time the bounce notification was recorded.
458
+ */
459
+ timestamp: string;
460
+ data: EventEmailOutOfBandBounceData;
461
+ };
462
+ /**
463
+ * Payload of the email.opened event.
464
+ */
465
+ type EventEmailOpenedData = EventEmailBase & {
466
+ /**
467
+ * IP address of the client that opened the email, or null when it is not known.
468
+ */
469
+ ip_address: string | null;
470
+ /**
471
+ * User-agent string of the client that opened the email, or null when it is not known.
472
+ */
473
+ user_agent: string | null;
474
+ };
475
+ /**
476
+ * The recipient opened the email (the tracking pixel was loaded). May fire more than once per recipient.
477
+ */
478
+ type EventEmailOpened = {
479
+ /**
480
+ * Event type.
481
+ */
482
+ type: "email.opened";
483
+ /**
484
+ * Time the open was recorded.
485
+ */
486
+ timestamp: string;
487
+ data: EventEmailOpenedData;
488
+ };
489
+ /**
490
+ * Payload of the email.list_unsubscribed event.
491
+ */
492
+ type EventEmailListUnsubscribedData = EventEmailBase;
493
+ /**
494
+ * Recipient unsubscribed via the RFC 8058 one-click List-Unsubscribe mechanism. Fires once per recipient.
495
+ */
496
+ type EventEmailListUnsubscribed = {
497
+ /**
498
+ * Event type.
499
+ */
500
+ type: "email.list_unsubscribed";
501
+ /**
502
+ * Time the unsubscribe was recorded.
503
+ */
504
+ timestamp: string;
505
+ data: EventEmailListUnsubscribedData;
506
+ };
507
+ /**
508
+ * Payload of the email.delivered event.
509
+ */
510
+ type EventEmailDeliveredData = EventEmailBase;
511
+ /**
512
+ * An outbound email reached the recipient's mail server and was accepted.
513
+ */
514
+ type EventEmailDelivered = {
515
+ /**
516
+ * Event type.
517
+ */
518
+ type: "email.delivered";
519
+ /**
520
+ * Time the recipient's mail server accepted the message.
521
+ */
522
+ timestamp: string;
523
+ data: EventEmailDeliveredData;
524
+ };
525
+ /**
526
+ * Payload of the email.deferred event.
527
+ */
528
+ type EventEmailDeferredData = EventEmailBase & {
529
+ bounce_type: EmailBounceType;
530
+ /**
531
+ * Numeric bounce classification for fine-grained deliverability triage, or null when the receiving server's response could not be classified. Distinguishes, for example, a greylisting deferral from a full mailbox.
532
+ *
533
+ */
534
+ bounce_class: number | null;
535
+ /**
536
+ * Human-readable reason the receiving mail server gave for the deferral, or null when none was provided.
537
+ */
538
+ defer_reason: string | null;
539
+ /**
540
+ * The IP address used to send this message, or null when it is not known.
541
+ */
542
+ sending_ip: string | null;
543
+ };
544
+ /**
545
+ * The recipient's mail server temporarily refused the email; delivery will be retried. May fire more than once per recipient.
546
+ */
547
+ type EventEmailDeferred = {
548
+ /**
549
+ * Event type.
550
+ */
551
+ type: "email.deferred";
552
+ /**
553
+ * Time the deferral was recorded.
554
+ */
555
+ timestamp: string;
556
+ data: EventEmailDeferredData;
557
+ };
558
+ /**
559
+ * Payload of the email.complained event.
560
+ */
561
+ type EventEmailComplainedData = EventEmailBase & {
562
+ /**
563
+ * The kind of feedback the mailbox provider reported (such as `abuse` or `fraud`), or null when the provider did not specify one.
564
+ */
565
+ feedback_type: string | null;
566
+ };
567
+ /**
568
+ * The recipient marked the email as spam through their mailbox provider's feedback loop. Fires once per recipient.
569
+ */
570
+ type EventEmailComplained = {
571
+ /**
572
+ * Event type.
573
+ */
574
+ type: "email.complained";
575
+ /**
576
+ * Time the complaint was recorded.
577
+ */
578
+ timestamp: string;
579
+ data: EventEmailComplainedData;
580
+ };
581
+ /**
582
+ * Payload of the email.clicked event.
583
+ */
584
+ type EventEmailClickedData = EventEmailBase & {
585
+ /**
586
+ * The URL the recipient clicked.
587
+ */
588
+ url: string;
589
+ /**
590
+ * IP address of the client that clicked the link, or null when it is not known.
591
+ */
592
+ ip_address: string | null;
593
+ /**
594
+ * User-agent string of the client that clicked the link, or null when it is not known.
595
+ */
596
+ user_agent: string | null;
597
+ };
598
+ /**
599
+ * The recipient clicked a tracked link in the email. May fire more than once per recipient.
600
+ */
601
+ type EventEmailClicked = {
602
+ /**
603
+ * Event type.
604
+ */
605
+ type: "email.clicked";
606
+ /**
607
+ * Time the click was recorded.
608
+ */
609
+ timestamp: string;
610
+ data: EventEmailClickedData;
611
+ };
612
+ /**
613
+ * Payload of the email.bounced event.
614
+ */
615
+ type EventEmailBouncedData = EventEmailBase & {
616
+ bounce_type: EmailBounceType;
617
+ /**
618
+ * Numeric bounce classification for fine-grained deliverability triage, or null when the receiving server's response could not be classified. Lets you distinguish, for example, a DNS failure from a spam block when both would be `bounce_type: soft` or `bounce_type: block`.
619
+ *
620
+ */
621
+ bounce_class: number | null;
622
+ /**
623
+ * SMTP reply code returned by the receiving mail server, or null when none was provided.
624
+ */
625
+ bounce_code: string | null;
626
+ /**
627
+ * Human-readable reason the receiving mail server gave for the bounce, or null when none was provided.
628
+ */
629
+ bounce_description: string | null;
630
+ /**
631
+ * The IP address used to send this message, or null when it is not known.
632
+ */
633
+ sending_ip: string | null;
634
+ };
635
+ /**
636
+ * An outbound email permanently failed at the recipient's mail server. Fires once per recipient.
637
+ */
638
+ type EventEmailBounced = {
639
+ /**
640
+ * Event type.
641
+ */
642
+ type: "email.bounced";
643
+ /**
644
+ * Time the bounce was recorded.
645
+ */
646
+ timestamp: string;
647
+ data: EventEmailBouncedData;
648
+ };
649
+ /**
650
+ * Payload of the email.accepted event.
651
+ */
652
+ type EventEmailAcceptedData = EventEmailBase;
653
+ /**
654
+ * Bird accepted the email send and is preparing to deliver. Fires once per requested recipient at acceptance time.
655
+ */
656
+ type EventEmailAccepted = {
657
+ /**
658
+ * Event type.
659
+ */
660
+ type: "email.accepted";
661
+ /**
662
+ * Time Bird accepted the send.
663
+ */
664
+ timestamp: string;
665
+ data: EventEmailAcceptedData;
666
+ };
667
+ /**
668
+ * A sending domain completed DNS verification successfully. Payload schema not yet finalized.
669
+ */
670
+ type EventDomainVerified = {
671
+ /**
672
+ * Event type.
673
+ */
674
+ type: "domain.verified";
675
+ /**
676
+ * When the event occurred.
677
+ */
678
+ timestamp: string;
679
+ /**
680
+ * Event payload. The fields for this event are not yet finalized.
681
+ */
682
+ data: {
683
+ [key: string]: never;
684
+ };
685
+ };
686
+ /**
687
+ * A sending domain failed DNS verification. Payload schema not yet finalized.
688
+ */
689
+ type EventDomainFailed = {
690
+ /**
691
+ * Event type.
692
+ */
693
+ type: "domain.failed";
694
+ /**
695
+ * When the event occurred.
696
+ */
697
+ timestamp: string;
698
+ /**
699
+ * Event payload. The fields for this event are not yet finalized.
700
+ */
701
+ data: {
702
+ [key: string]: never;
703
+ };
704
+ };
705
+ /**
706
+ * Discriminated union of every webhook event the Bird platform emits.
707
+ * Each variant is the full delivery body: `type` names the event, `timestamp` is when the event occurred, and `data` carries the event-specific payload. The `type` property selects the variant — SDKs that consume this schema (openapi-typescript, oapi-codegen) generate a narrowed union keyed on `type`, so customer code can switch on the event id and access the variant-specific payload fields without casting.
708
+ * Delivery metadata (the event id and per-attempt signature headers) rides in HTTP headers per Standard Webhooks and is handled by the SDK's webhook verification helper, which returns one of these variants.
709
+ *
710
+ */
711
+ type WebhookEvent = ({
712
+ type: "domain.failed";
713
+ } & EventDomainFailed) | ({
714
+ type: "domain.verified";
715
+ } & EventDomainVerified) | ({
716
+ type: "email.accepted";
717
+ } & EventEmailAccepted) | ({
718
+ type: "email.bounced";
719
+ } & EventEmailBounced) | ({
720
+ type: "email.clicked";
721
+ } & EventEmailClicked) | ({
722
+ type: "email.complained";
723
+ } & EventEmailComplained) | ({
724
+ type: "email.deferred";
725
+ } & EventEmailDeferred) | ({
726
+ type: "email.delivered";
727
+ } & EventEmailDelivered) | ({
728
+ type: "email.list_unsubscribed";
729
+ } & EventEmailListUnsubscribed) | ({
730
+ type: "email.opened";
731
+ } & EventEmailOpened) | ({
732
+ type: "email.out_of_band_bounce";
733
+ } & EventEmailOutOfBandBounce) | ({
734
+ type: "email.processed";
735
+ } & EventEmailProcessed) | ({
736
+ type: "email.received";
737
+ } & EventEmailReceived) | ({
738
+ type: "email.rejected";
739
+ } & EventEmailRejected) | ({
740
+ type: "email.unsubscribed";
741
+ } & EventEmailUnsubscribed) | ({
742
+ type: "email_suppression.created";
743
+ } & EventEmailSuppressionCreated);
744
+ /**
745
+ * File attached to an email send. The attachment bytes are passed as base64-encoded `content` directly in the request body (required). The `path` field (provide a URL and Bird fetches the attachment for you) is a preview feature and currently unavailable. Requests are rejected with 422 if `content` is missing — `path` alone does not satisfy the schema. When `path` becomes generally available, the schema will be relaxed so that exactly one of `content` or `path` is required.
746
+ * Inline images for `<img src="cid:..."/>` references in the HTML body use the `content_id` field together with `content`.
747
+ * Total message size (body + inline images + all attachments) is capped at **20 MB on the wire (post-base64)**. Sends above this limit are rejected. As a rule of thumb, raw file content should stay under ~15 MB to leave headroom after base64 encoding.
748
+ * Recipient-side delivery reality: most consumer inboxes cap at 20–25 MB (Gmail 25 MB, Outlook desktop 20 MB, Exchange corporate often 10 MB). Sends close to Bird's 20 MB cap may be accepted by Bird but bounce at the recipient's mail server.
749
+ * Sends with attachments cannot use `POST /v1/emails/batch`; use the single-send endpoint instead. Certain executable / script content types are rejected at validation time.
750
+ *
751
+ */
752
+ type EmailAttachment = {
753
+ /**
754
+ * Filename shown to the recipient. Required.
755
+ */
756
+ filename: string;
757
+ /**
758
+ * Base64-encoded attachment bytes. Required. Counts against the 20 MB per-send wire cap.
759
+ *
760
+ */
761
+ content: string;
762
+ /**
763
+ * Preview feature — provide a URL and Bird fetches the attachment for you. Currently unavailable. Use `content` instead. The schema currently requires `content`, so a request with only `path` is rejected with 422 for missing `content`; a request supplying both `content` and `path` is rejected with 422 `unsupported_feature` until this preview ships. When generally available: HTTPS-only, single redirect followed and re-validated, private IP ranges blocked, request timeout enforced, fetched content counts against the 20 MB per-send wire cap.
764
+ *
765
+ */
766
+ path?: string;
767
+ /**
768
+ * MIME type. Inferred from `filename` extension when omitted. Used to enforce the blocklist of disallowed executable / script types.
769
+ *
770
+ */
771
+ content_type?: string;
772
+ /**
773
+ * RFC 2392 Content-ID. When set, the attachment is rendered inline and can be referenced from the HTML body as `<img src="cid:{content_id}"/>`. When omitted, the attachment is rendered as a regular file attachment.
774
+ *
775
+ */
776
+ content_id?: string;
777
+ };
778
+ /**
779
+ * An email address with an optional display name.
780
+ */
781
+ type EmailAddress = {
782
+ /**
783
+ * Email address.
784
+ */
785
+ email: string;
786
+ /**
787
+ * Display name shown alongside the address in mail clients.
788
+ */
789
+ name?: string;
790
+ };
791
+ /**
792
+ * A sender or recipient address. Accepts a plain email string (`jane@example.com`), an RFC 5322 mailbox string with an embedded display name (`Jane Doe <jane@example.com>`), or an object carrying the address and an optional display name. All forms can be mixed freely within one request; responses always return the object form.
793
+ *
794
+ */
795
+ type EmailAddressInput = string | EmailAddress;
796
+ type EmailMessageSendRequest = {
797
+ /**
798
+ * Sender address, as a plain email string, an RFC 5322 mailbox string (`Jane <jane@example.com>`), or an object with an optional display name. Must be from a verified domain in this workspace.
799
+ */
800
+ from: EmailAddressInput;
801
+ /**
802
+ * Primary recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@example.com>`), or an object with an optional display name.
803
+ */
804
+ to: Array<EmailAddressInput>;
805
+ /**
806
+ * CC recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@example.com>`), or an object with an optional display name.
807
+ */
808
+ cc?: Array<EmailAddressInput>;
809
+ /**
810
+ * BCC recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@example.com>`), or an object with an optional display name.
811
+ */
812
+ bcc?: Array<EmailAddressInput>;
813
+ /**
814
+ * Message subject line.
815
+ */
816
+ subject: string;
817
+ /**
818
+ * HTML body. At least one of html or text must be provided.
819
+ */
820
+ html?: string;
821
+ /**
822
+ * Plain-text body. At least one of html or text must be provided.
823
+ */
824
+ text?: string;
825
+ /**
826
+ * Reply-To addresses, each a plain email string, an RFC 5322 mailbox string, or an object with an optional display name. RFC 5322 allows multiple. Every recipient reply hits all listed addresses, so 1-2 is typical; the 25 cap exists to prevent runaway header sizes that some MTAs reject.
827
+ *
828
+ */
829
+ reply_to?: Array<EmailAddressInput>;
830
+ /**
831
+ * Custom email headers as key-value pairs.
832
+ */
833
+ headers?: {
834
+ [key: string]: string;
835
+ };
836
+ /**
837
+ * Structured `{name, value}` labels for **filtering and analytics**. Tags become first-class query dimensions: filter the list endpoint by tag name, slice analytics rollups by tag, and surface in webhook payloads. Cap: 20 tags per send. Use tags for low-cardinality dimensions (`category`, `experiment_variant`, `template_id`). For arbitrary structured context that you do not need as a filter dimension, use `metadata` instead.
838
+ *
839
+ */
840
+ tags?: Array<EmailTag>;
841
+ /**
842
+ * Arbitrary JSON object **stored, returned on API reads, and echoed in webhook payloads**. Path-queryable in analytics (e.g. filter on `metadata.order_id`) but not surfaced as a first-class dashboard filter dimension. Cap: 2 KB serialized. Use metadata for per-send context like internal IDs, foreign keys, and structured payloads you want round-tripped through events. For low-cardinality filterable labels, use `tags` instead.
843
+ *
844
+ */
845
+ metadata?: {
846
+ [key: string]: unknown;
847
+ };
848
+ /**
849
+ * Whether to track open events for this message.
850
+ */
851
+ track_opens?: boolean;
852
+ /**
853
+ * Whether to track click events for this message.
854
+ */
855
+ track_clicks?: boolean;
856
+ /**
857
+ * ID of the IP pool to send from (`ipp_` prefix), or `ipp_shared` to route through the shared pool explicitly. Omit to use your organization's default pool. An unknown pool, or a pool with no dedicated IPs available to send from, is rejected with a `422`.
858
+ *
859
+ */
860
+ ip_pool?: string;
861
+ /**
862
+ * Content classification — independent of which endpoint you use. Controls suppression policy: `marketing` blocks on all suppression reasons (use for marketing content); `transactional` allows delivery through complaint and unsubscribe suppressions (use for receipts, password resets, and similar operational messages). Default: transactional.
863
+ *
864
+ */
865
+ category?: "marketing" | "transactional";
866
+ /**
867
+ * Preview feature — threaded replies. Currently unavailable; supplying this field returns `422 unsupported_feature`. When generally available, sets In-Reply-To and References headers automatically.
868
+ */
869
+ in_reply_to_message_id?: EmailId;
870
+ /**
871
+ * File attachments. Total message size (body + inline images + all attachments) capped at 20 MB post-base64. Raw file content should stay under ~15 MB to leave room after encoding. Sends with attachments cannot use `POST /v1/emails/batch`; use the single-send endpoint. See the EmailAttachment schema for the full field contract.
872
+ *
873
+ */
874
+ attachments?: Array<EmailAttachment>;
875
+ /**
876
+ * Preview feature — send-later scheduling. Currently unavailable; supplying this field returns `422 unsupported_feature`.
877
+ */
878
+ scheduled_at?: string;
879
+ /**
880
+ * Preview feature — contact-targeted sends. Currently unavailable; supplying this field returns `422 unsupported_feature`.
881
+ */
882
+ contact_id?: string;
883
+ /**
884
+ * Preview feature — topic-gated sends. Currently unavailable; supplying this field returns `422 unsupported_feature`. When generally available, a non-empty `topic_id` gates delivery on the recipient's opt-in state for that topic — if the recipient is opt_out, the send is silently suppressed and an `email.suppressed` event fires with `reason: topic_opt_out`.
885
+ *
886
+ */
887
+ topic_id?: string;
888
+ };
889
+ /**
890
+ * Attachment metadata returned on API reads. The original content is not echoed back — only the metadata needed for display and audit. To fetch the raw attachment content (when storage is enabled), use `GET /v1/email/messages/{email_id}/attachments/{attachment_id}` — endpoint reserved for a future content-retention product.
891
+ *
892
+ */
893
+ type EmailAttachmentRef = {
894
+ /**
895
+ * Attachment ID, stable per email send.
896
+ */
897
+ id?: string;
898
+ /**
899
+ * Filename as shown to the recipient.
900
+ */
901
+ filename: string;
902
+ /**
903
+ * Resolved MIME type at send time.
904
+ */
905
+ content_type?: string;
906
+ /**
907
+ * Decoded size in bytes.
908
+ */
909
+ size: number;
910
+ /**
911
+ * True when the attachment was sent inline via a `content_id` reference in the HTML body, false for regular file attachments.
912
+ *
913
+ */
914
+ inline?: boolean;
915
+ /**
916
+ * The Content-ID set at send time, when the attachment was inline.
917
+ */
918
+ content_id?: string | null;
919
+ };
920
+ type EmailMessage = {
921
+ /**
922
+ * Message ID.
923
+ */
924
+ readonly id: EmailId;
925
+ /**
926
+ * Sender address. `name` is present when a display name was provided on the send.
927
+ */
928
+ from: EmailAddress;
929
+ /**
930
+ * Primary recipients. Length is the recipient count; use the broadcasts endpoint for audience-targeted sends. Each entry's `name` is present when a display name was provided on the send.
931
+ */
932
+ to: Array<EmailAddress>;
933
+ /**
934
+ * CC recipients.
935
+ */
936
+ cc?: Array<EmailAddress>;
937
+ /**
938
+ * BCC recipients.
939
+ */
940
+ bcc?: Array<EmailAddress>;
941
+ /**
942
+ * Message subject line.
943
+ */
944
+ subject: string;
945
+ /**
946
+ * Content classification. Controls suppression policy — `marketing` blocks on all suppression reasons; `transactional` allows delivery through complaint and unsubscribe suppressions.
947
+ *
948
+ */
949
+ category: "marketing" | "transactional";
950
+ /**
951
+ * Reply-To addresses, if set on the send. Empty/null when no Reply-To was provided.
952
+ */
953
+ reply_to?: Array<EmailAddress> | null;
954
+ /**
955
+ * Aggregate delivery status derived from recipient states. `accepted` means Bird has the send and is preparing to deliver. `processed` means Bird has processed the message and queued it for delivery to the recipient's mail server.
956
+ *
957
+ */
958
+ readonly status: "accepted" | "processed" | "deferred" | "delivered" | "partial_failure" | "bounced" | "complained" | "rejected";
959
+ /**
960
+ * Number of recipients currently in the `accepted` state — Bird has the send and is preparing to deliver.
961
+ */
962
+ readonly accepted_count: number;
963
+ /**
964
+ * Number of recipients for whom Bird has processed the message and queued it for delivery.
965
+ */
966
+ readonly processed_count: number;
967
+ /**
968
+ * Number of recipients whose messages were accepted by the remote MTA.
969
+ */
970
+ readonly delivered_count: number;
971
+ /**
972
+ * Number of recipients that resulted in a permanent delivery failure.
973
+ */
974
+ readonly bounced_count: number;
975
+ /**
976
+ * Number of recipients that reported spam.
977
+ */
978
+ readonly complained_count: number;
979
+ /**
980
+ * Number of recipients in transient delivery deferral; the provider is retrying.
981
+ */
982
+ readonly deferred_count: number;
983
+ /**
984
+ * Number of recipients rejected before delivery. See the per-recipient `rejection_reason` field on `GET /v1/emails/{id}/recipients` for the specific cause (suppression match, transmission failure, generation failure, or policy refusal).
985
+ *
986
+ */
987
+ readonly rejected_count: number;
988
+ /**
989
+ * Time between Bird accepting the send and the message being processed for delivery, in milliseconds, for the fastest recipient. Null until the first recipient reaches `processed`.
990
+ *
991
+ */
992
+ readonly processing_latency_ms?: number | null;
993
+ /**
994
+ * Time between the message being processed and the receiving mail server accepting it, in milliseconds, for the fastest delivered recipient. Null until the first recipient is delivered.
995
+ *
996
+ */
997
+ readonly delivery_latency_ms?: number | null;
998
+ /**
999
+ * End-to-end accept → delivered time for the fastest delivered recipient, in milliseconds. Null until the first recipient is delivered.
1000
+ *
1001
+ */
1002
+ readonly total_latency_ms?: number | null;
1003
+ /**
1004
+ * Total open events across all recipients.
1005
+ */
1006
+ readonly open_count: number;
1007
+ /**
1008
+ * Total click events across all recipients.
1009
+ */
1010
+ readonly click_count: number;
1011
+ /**
1012
+ * Structured `{name, value}` filter labels applied to this send. See EmailMessageSendRequest for the tags vs metadata distinction.
1013
+ */
1014
+ tags?: Array<EmailTag>;
1015
+ /**
1016
+ * Arbitrary JSON metadata stored on the message object and echoed in webhook payloads. See EmailMessageSendRequest for the tags vs metadata distinction.
1017
+ */
1018
+ metadata?: {
1019
+ [key: string]: unknown;
1020
+ };
1021
+ /**
1022
+ * Attachment metadata for the send. Empty when no attachments were included. Raw content is not echoed; use the future content-retrieval endpoint when storage is enabled.
1023
+ */
1024
+ attachments?: Array<EmailAttachmentRef>;
1025
+ /**
1026
+ * Whether open tracking is enabled for this send.
1027
+ */
1028
+ track_opens: boolean;
1029
+ /**
1030
+ * Whether click tracking is enabled for this send.
1031
+ */
1032
+ track_clicks: boolean;
1033
+ /**
1034
+ * When the send request was accepted.
1035
+ */
1036
+ readonly created_at: string;
1037
+ /**
1038
+ * Thread this message belongs to. Null until threading is enabled.
1039
+ */
1040
+ readonly thread_id?: string | null;
1041
+ /**
1042
+ * The message this one is a reply to, if any.
1043
+ */
1044
+ readonly in_reply_to_message_id?: string | null;
1045
+ /**
1046
+ * When all recipients reached a terminal delivered state, or null if not yet fully delivered.
1047
+ */
1048
+ readonly delivered_at?: string | null;
1049
+ };
1050
+ type ListEmailMessagesData = {
1051
+ body?: never;
1052
+ path?: never;
1053
+ query?: {
1054
+ /**
1055
+ * Maximum number of items to return per page.
1056
+ */
1057
+ limit?: number;
1058
+ /**
1059
+ * Cursor from the `next_cursor` field of a previous list response. Returns items immediately after the cursor position in the current sort order.
1060
+ */
1061
+ starting_after?: string;
1062
+ /**
1063
+ * Cursor from the `prev_cursor` field of a previous list response. Returns items immediately before the cursor position in the current sort order.
1064
+ */
1065
+ ending_before?: string;
1066
+ /**
1067
+ * Return only resources created strictly after this timestamp. RFC 3339 / ISO 8601 with timezone.
1068
+ */
1069
+ created_after?: string;
1070
+ /**
1071
+ * Return only resources created strictly before this timestamp. RFC 3339 / ISO 8601 with timezone.
1072
+ */
1073
+ created_before?: string;
1074
+ /**
1075
+ * Filter by aggregate delivery status.
1076
+ */
1077
+ status?: "accepted" | "processed" | "deferred" | "delivered" | "partial_failure" | "bounced" | "complained" | "rejected";
1078
+ /**
1079
+ * Filter by tag. Accepts `name` to match any send carrying that tag name, or `name:value` to match a specific tag pair (e.g. `category:welcome`). For filtering on arbitrary `metadata` fields, use the metadata path-filter parameters instead.
1080
+ *
1081
+ */
1082
+ tag?: string;
1083
+ /**
1084
+ * Filter by category.
1085
+ */
1086
+ category?: "marketing" | "transactional";
1087
+ /**
1088
+ * Filter by recipient address. Exact match against any `to`/`cc`/`bcc` recipient on the message; normalised to lowercase before comparison.
1089
+ *
1090
+ */
1091
+ to?: string;
1092
+ /**
1093
+ * Filter by sender address. Exact match against the message `from` field; normalised to lowercase before comparison.
1094
+ *
1095
+ */
1096
+ from?: string;
1097
+ };
1098
+ url: "/v1/email/messages";
1099
+ };
1100
+
1101
+ type AuthToken = string | undefined;
1102
+ interface Auth {
1103
+ /**
1104
+ * Which part of the request do we use to send the auth?
1105
+ *
1106
+ * @default 'header'
1107
+ */
1108
+ in?: "header" | "query" | "cookie";
1109
+ /**
1110
+ * Header or query parameter name.
1111
+ *
1112
+ * @default 'Authorization'
1113
+ */
1114
+ name?: string;
1115
+ scheme?: "basic" | "bearer";
1116
+ type: "apiKey" | "http";
1117
+ }
1118
+
1119
+ interface SerializerOptions<T> {
1120
+ /**
1121
+ * @default true
1122
+ */
1123
+ explode: boolean;
1124
+ style: T;
1125
+ }
1126
+ type ArrayStyle = "form" | "spaceDelimited" | "pipeDelimited";
1127
+ type ObjectStyle = "form" | "deepObject";
1128
+
1129
+ type QuerySerializer = (query: Record<string, unknown>) => string;
1130
+ type BodySerializer = (body: unknown) => unknown;
1131
+ type QuerySerializerOptionsObject = {
1132
+ allowReserved?: boolean;
1133
+ array?: Partial<SerializerOptions<ArrayStyle>>;
1134
+ object?: Partial<SerializerOptions<ObjectStyle>>;
1135
+ };
1136
+ type QuerySerializerOptions = QuerySerializerOptionsObject & {
1137
+ /**
1138
+ * Per-parameter serialization overrides. When provided, these settings
1139
+ * override the global array/object settings for specific parameter names.
1140
+ */
1141
+ parameters?: Record<string, QuerySerializerOptionsObject>;
1142
+ };
1143
+
1144
+ type HttpMethod = "connect" | "delete" | "get" | "head" | "options" | "patch" | "post" | "put" | "trace";
1145
+ type Client$1<RequestFn = never, Config = unknown, MethodFn = never, BuildUrlFn = never, SseFn = never> = {
1146
+ /**
1147
+ * Returns the final request URL.
1148
+ */
1149
+ buildUrl: BuildUrlFn;
1150
+ getConfig: () => Config;
1151
+ request: RequestFn;
1152
+ setConfig: (config: Config) => Config;
1153
+ } & {
1154
+ [K in HttpMethod]: MethodFn;
1155
+ } & ([SseFn] extends [never] ? {
1156
+ sse?: never;
1157
+ } : {
1158
+ sse: {
1159
+ [K in HttpMethod]: SseFn;
1160
+ };
1161
+ });
1162
+ interface Config$1 {
1163
+ /**
1164
+ * Auth token or a function returning auth token. The resolved value will be
1165
+ * added to the request payload as defined by its `security` array.
1166
+ */
1167
+ auth?: ((auth: Auth) => Promise<AuthToken> | AuthToken) | AuthToken;
1168
+ /**
1169
+ * A function for serializing request body parameter. By default,
1170
+ * {@link JSON.stringify()} will be used.
1171
+ */
1172
+ bodySerializer?: BodySerializer | null;
1173
+ /**
1174
+ * An object containing any HTTP headers that you want to pre-populate your
1175
+ * `Headers` object with.
1176
+ *
1177
+ * {@link https://developer.mozilla.org/docs/Web/API/Headers/Headers#init See more}
1178
+ */
1179
+ headers?: RequestInit["headers"] | Record<string, string | number | boolean | (string | number | boolean)[] | null | undefined | unknown>;
1180
+ /**
1181
+ * The request method.
1182
+ *
1183
+ * {@link https://developer.mozilla.org/docs/Web/API/fetch#method See more}
1184
+ */
1185
+ method?: Uppercase<HttpMethod>;
1186
+ /**
1187
+ * A function for serializing request query parameters. By default, arrays
1188
+ * will be exploded in form style, objects will be exploded in deepObject
1189
+ * style, and reserved characters are percent-encoded.
1190
+ *
1191
+ * This method will have no effect if the native `paramsSerializer()` Axios
1192
+ * API function is used.
1193
+ *
1194
+ * {@link https://swagger.io/docs/specification/serialization/#query View examples}
1195
+ */
1196
+ querySerializer?: QuerySerializer | QuerySerializerOptions;
1197
+ /**
1198
+ * A function validating request data. This is useful if you want to ensure
1199
+ * the request conforms to the desired shape, so it can be safely sent to
1200
+ * the server.
1201
+ */
1202
+ requestValidator?: (data: unknown) => Promise<unknown>;
1203
+ /**
1204
+ * A function transforming response data before it's returned. This is useful
1205
+ * for post-processing data, e.g., converting ISO strings into Date objects.
1206
+ */
1207
+ responseTransformer?: (data: unknown) => Promise<unknown>;
1208
+ /**
1209
+ * A function validating response data. This is useful if you want to ensure
1210
+ * the response conforms to the desired shape, so it can be safely passed to
1211
+ * the transformers and returned to the user.
1212
+ */
1213
+ responseValidator?: (data: unknown) => Promise<unknown>;
1214
+ }
1215
+
1216
+ type ServerSentEventsOptions<TData = unknown> = Omit<RequestInit, "method"> & Pick<Config$1, "method" | "responseTransformer" | "responseValidator"> & {
1217
+ /**
1218
+ * Fetch API implementation. You can use this option to provide a custom
1219
+ * fetch instance.
1220
+ *
1221
+ * @default globalThis.fetch
1222
+ */
1223
+ fetch?: typeof fetch;
1224
+ /**
1225
+ * Implementing clients can call request interceptors inside this hook.
1226
+ */
1227
+ onRequest?: (url: string, init: RequestInit) => Promise<Request>;
1228
+ /**
1229
+ * Callback invoked when a network or parsing error occurs during streaming.
1230
+ *
1231
+ * This option applies only if the endpoint returns a stream of events.
1232
+ *
1233
+ * @param error The error that occurred.
1234
+ */
1235
+ onSseError?: (error: unknown) => void;
1236
+ /**
1237
+ * Callback invoked when an event is streamed from the server.
1238
+ *
1239
+ * This option applies only if the endpoint returns a stream of events.
1240
+ *
1241
+ * @param event Event streamed from the server.
1242
+ * @returns Nothing (void).
1243
+ */
1244
+ onSseEvent?: (event: StreamEvent<TData>) => void;
1245
+ serializedBody?: RequestInit["body"];
1246
+ /**
1247
+ * Default retry delay in milliseconds.
1248
+ *
1249
+ * This option applies only if the endpoint returns a stream of events.
1250
+ *
1251
+ * @default 3000
1252
+ */
1253
+ sseDefaultRetryDelay?: number;
1254
+ /**
1255
+ * Maximum number of retry attempts before giving up.
1256
+ */
1257
+ sseMaxRetryAttempts?: number;
1258
+ /**
1259
+ * Maximum retry delay in milliseconds.
1260
+ *
1261
+ * Applies only when exponential backoff is used.
1262
+ *
1263
+ * This option applies only if the endpoint returns a stream of events.
1264
+ *
1265
+ * @default 30000
1266
+ */
1267
+ sseMaxRetryDelay?: number;
1268
+ /**
1269
+ * Optional sleep function for retry backoff.
1270
+ *
1271
+ * Defaults to using `setTimeout`.
1272
+ */
1273
+ sseSleepFn?: (ms: number) => Promise<void>;
1274
+ url: string;
1275
+ };
1276
+ interface StreamEvent<TData = unknown> {
1277
+ data: TData;
1278
+ event?: string;
1279
+ id?: string;
1280
+ retry?: number;
1281
+ }
1282
+ type ServerSentEventsResult<TData = unknown, TReturn = void, TNext = unknown> = {
1283
+ stream: AsyncGenerator<TData extends Record<string, unknown> ? TData[keyof TData] : TData, TReturn, TNext>;
1284
+ };
1285
+
1286
+ type ErrInterceptor<Err, Res, Req, Options> = (error: Err,
1287
+ /** response may be undefined due to a network error where no response object is produced */
1288
+ response: Res | undefined,
1289
+ /** request may be undefined, because error may be from building the request object itself */
1290
+ request: Req | undefined, options: Options) => Err | Promise<Err>;
1291
+ type ReqInterceptor<Req, Options> = (request: Req, options: Options) => Req | Promise<Req>;
1292
+ type ResInterceptor<Res, Req, Options> = (response: Res, request: Req, options: Options) => Res | Promise<Res>;
1293
+ declare class Interceptors<Interceptor> {
1294
+ fns: Array<Interceptor | null>;
1295
+ clear(): void;
1296
+ eject(id: number | Interceptor): void;
1297
+ exists(id: number | Interceptor): boolean;
1298
+ getInterceptorIndex(id: number | Interceptor): number;
1299
+ update(id: number | Interceptor, fn: Interceptor): number | Interceptor | false;
1300
+ use(fn: Interceptor): number;
1301
+ }
1302
+ interface Middleware<Req, Res, Err, Options> {
1303
+ error: Interceptors<ErrInterceptor<Err, Res, Req, Options>>;
1304
+ request: Interceptors<ReqInterceptor<Req, Options>>;
1305
+ response: Interceptors<ResInterceptor<Res, Req, Options>>;
1306
+ }
1307
+
1308
+ type ResponseStyle = "data" | "fields";
1309
+ interface Config<T extends ClientOptions = ClientOptions> extends Omit<RequestInit, "body" | "headers" | "method">, Config$1 {
1310
+ /**
1311
+ * Base URL for all requests made by this client.
1312
+ */
1313
+ baseUrl?: T["baseUrl"];
1314
+ /**
1315
+ * Fetch API implementation. You can use this option to provide a custom
1316
+ * fetch instance.
1317
+ *
1318
+ * @default globalThis.fetch
1319
+ */
1320
+ fetch?: typeof fetch;
1321
+ /**
1322
+ * Please don't use the Fetch client for Next.js applications. The `next`
1323
+ * options won't have any effect.
1324
+ *
1325
+ * Install {@link https://www.npmjs.com/package/@hey-api/client-next `@hey-api/client-next`} instead.
1326
+ */
1327
+ next?: never;
1328
+ /**
1329
+ * Return the response data parsed in a specified format. By default, `auto`
1330
+ * will infer the appropriate method from the `Content-Type` response header.
1331
+ * You can override this behavior with any of the {@link Body} methods.
1332
+ * Select `stream` if you don't want to parse response data at all.
1333
+ *
1334
+ * @default 'auto'
1335
+ */
1336
+ parseAs?: "arrayBuffer" | "auto" | "blob" | "formData" | "json" | "stream" | "text";
1337
+ /**
1338
+ * Should we return only data or multiple fields (data, error, response, etc.)?
1339
+ *
1340
+ * @default 'fields'
1341
+ */
1342
+ responseStyle?: ResponseStyle;
1343
+ /**
1344
+ * Throw an error instead of returning it in the response?
1345
+ *
1346
+ * @default false
1347
+ */
1348
+ throwOnError?: T["throwOnError"];
1349
+ }
1350
+ interface RequestOptions<TData = unknown, TResponseStyle extends ResponseStyle = "fields", ThrowOnError extends boolean = boolean, Url extends string = string> extends Config<{
1351
+ responseStyle: TResponseStyle;
1352
+ throwOnError: ThrowOnError;
1353
+ }>, Pick<ServerSentEventsOptions<TData>, "onRequest" | "onSseError" | "onSseEvent" | "sseDefaultRetryDelay" | "sseMaxRetryAttempts" | "sseMaxRetryDelay"> {
1354
+ /**
1355
+ * Any body that you want to add to your request.
1356
+ *
1357
+ * {@link https://developer.mozilla.org/docs/Web/API/fetch#body}
1358
+ */
1359
+ body?: unknown;
1360
+ path?: Record<string, unknown>;
1361
+ query?: Record<string, unknown>;
1362
+ /**
1363
+ * Security mechanism(s) to use for the request.
1364
+ */
1365
+ security?: ReadonlyArray<Auth>;
1366
+ url: Url;
1367
+ }
1368
+ interface ResolvedRequestOptions<TResponseStyle extends ResponseStyle = "fields", ThrowOnError extends boolean = boolean, Url extends string = string> extends RequestOptions<unknown, TResponseStyle, ThrowOnError, Url> {
1369
+ headers: Headers;
1370
+ serializedBody?: string;
1371
+ }
1372
+ type RequestResult<TData = unknown, TError = unknown, ThrowOnError extends boolean = boolean, TResponseStyle extends ResponseStyle = "fields"> = ThrowOnError extends true ? Promise<TResponseStyle extends "data" ? TData extends Record<string, unknown> ? TData[keyof TData] : TData : {
1373
+ data: TData extends Record<string, unknown> ? TData[keyof TData] : TData;
1374
+ request: Request;
1375
+ response: Response;
1376
+ }> : Promise<TResponseStyle extends "data" ? (TData extends Record<string, unknown> ? TData[keyof TData] : TData) | undefined : ({
1377
+ data: TData extends Record<string, unknown> ? TData[keyof TData] : TData;
1378
+ error: undefined;
1379
+ } | {
1380
+ data: undefined;
1381
+ error: TError extends Record<string, unknown> ? TError[keyof TError] : TError;
1382
+ }) & {
1383
+ /** request may be undefined, because error may be from building the request object itself */
1384
+ request?: Request;
1385
+ /** response may be undefined, because error may be from building the request object itself or from a network error */
1386
+ response?: Response;
1387
+ }>;
1388
+ interface ClientOptions {
1389
+ baseUrl?: string;
1390
+ responseStyle?: ResponseStyle;
1391
+ throwOnError?: boolean;
1392
+ }
1393
+ type MethodFn = <TData = unknown, TError = unknown, ThrowOnError extends boolean = false, TResponseStyle extends ResponseStyle = "fields">(options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, "method">) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
1394
+ type SseFn = <TData = unknown, TError = unknown, ThrowOnError extends boolean = false, TResponseStyle extends ResponseStyle = "fields">(options: Omit<RequestOptions<never, TResponseStyle, ThrowOnError>, "method">) => Promise<ServerSentEventsResult<TData, TError>>;
1395
+ type RequestFn = <TData = unknown, TError = unknown, ThrowOnError extends boolean = false, TResponseStyle extends ResponseStyle = "fields">(options: Omit<RequestOptions<TData, TResponseStyle, ThrowOnError>, "method"> & Pick<Required<RequestOptions<TData, TResponseStyle, ThrowOnError>>, "method">) => RequestResult<TData, TError, ThrowOnError, TResponseStyle>;
1396
+ type BuildUrlFn = <TData extends {
1397
+ body?: unknown;
1398
+ path?: Record<string, unknown>;
1399
+ query?: Record<string, unknown>;
1400
+ url: string;
1401
+ }>(options: TData & Options<TData>) => string;
1402
+ type Client = Client$1<RequestFn, Config, MethodFn, BuildUrlFn, SseFn> & {
1403
+ interceptors: Middleware<Request, Response, unknown, ResolvedRequestOptions>;
1404
+ };
1405
+ interface TDataShape {
1406
+ body?: unknown;
1407
+ headers?: unknown;
1408
+ path?: unknown;
1409
+ query?: unknown;
1410
+ url: string;
1411
+ }
1412
+ type OmitKeys<T, K> = Pick<T, Exclude<keyof T, K>>;
1413
+ type Options<TData extends TDataShape = TDataShape, ThrowOnError extends boolean = boolean, TResponse = unknown, TResponseStyle extends ResponseStyle = "fields"> = OmitKeys<RequestOptions<TResponse, TResponseStyle, ThrowOnError>, "body" | "path" | "query" | "url"> & ([TData] extends [never] ? unknown : Omit<TData, "url">);
1414
+
1415
+ /** Resolved per-attempt inputs handed to the hey-api SDK call. */
1416
+ interface CallContext {
1417
+ signal: AbortSignal;
1418
+ /** Merged headers: caller `headers` plus the resolved `Idempotency-Key`. */
1419
+ headers: Record<string, string>;
1420
+ }
1421
+ declare abstract class Resource {
1422
+ protected readonly core: BirdHTTPClient;
1423
+ protected readonly client: Client;
1424
+ constructor(core: BirdHTTPClient, client: Client);
1425
+ /** Run a single typed call through the lifecycle. */
1426
+ protected call<T>(method: string, options: RequestOptions$1 | undefined, invoke: (ctx: CallContext) => Promise<FetchOutcome<T>>): APIPromise<T>;
1427
+ /** Run a cursor-paginated list through the lifecycle (each page retried independently). */
1428
+ protected paginated<T>(method: string, options: RequestOptions$1 | undefined, invoke: (ctx: CallContext, cursor: string | undefined) => Promise<FetchOutcome<CursorPage<T>>>): PaginatedPromise<T>;
1429
+ }
1430
+
1431
+ /** Body for `bird.email.send`. */
1432
+ type EmailSendParams = EmailMessageSendRequest;
1433
+ /** Filters and cursor params for `bird.email.list`. */
1434
+ type EmailListQuery = NonNullable<ListEmailMessagesData["query"]>;
1435
+ /**
1436
+ * Channel-level defaults set at client construction. Field names mirror the
1437
+ * send params (so they read as pre-filled fields). Any field set here becomes
1438
+ * optional in `send` and is filled when omitted (per-send value wins).
1439
+ */
1440
+ type EmailChannelDefaults = Partial<Pick<EmailSendParams, "from" | "reply_to" | "category" | "track_opens" | "track_clicks" | "headers" | "tags" | "metadata">>;
1441
+ type PartialBy<T, K extends keyof T> = Omit<T, K> & Partial<Pick<T, K>>;
1442
+ /** Keys that carry a configured default — made optional in `send`. */
1443
+ type DefaultedKeys<D> = D extends object ? Extract<keyof D, keyof EmailSendParams> : never;
1444
+ /** `send` params with defaulted fields made optional. */
1445
+ type EmailSend<D> = PartialBy<EmailSendParams, DefaultedKeys<D>>;
1446
+ declare class EmailResource<D extends EmailChannelDefaults | undefined = undefined> extends Resource {
1447
+ #private;
1448
+ constructor(core: ConstructorParameters<typeof Resource>[0], client: ConstructorParameters<typeof Resource>[1], defaults?: D);
1449
+ /**
1450
+ * Send an email message. Resolves once the message is accepted for delivery
1451
+ * (the API's 202). Throws on failure — a 422 (unverified sender, all
1452
+ * recipients suppressed, validation) is a `BirdValidationError`. Fields set as
1453
+ * channel defaults may be omitted (per-send value wins).
1454
+ *
1455
+ * @example Send a message
1456
+ * // bird:snippet:start email.send
1457
+ * const msg = await bird.email.send({
1458
+ * from: { email: "onboarding@messagebird.dev", name: "Bird" },
1459
+ * to: ["delivered@messagebird.dev"],
1460
+ * subject: "Hello from Bird",
1461
+ * html: "<p>My first Bird email.</p>",
1462
+ * });
1463
+ * console.log(msg.id, msg.status); // "em_…", "accepted"
1464
+ * // bird:snippet:end email.send
1465
+ *
1466
+ * @example A richer send — cc/bcc, reply-to, tags, metadata, click-tracking off, and an idempotency key (safe to retry; the server dedupes)
1467
+ * await bird.email.send(
1468
+ * {
1469
+ * from: "hello@acme.com",
1470
+ * to: ["a@example.com", "b@example.com"],
1471
+ * cc: ["manager@example.com"],
1472
+ * reply_to: ["support@acme.com"],
1473
+ * subject: "Your March invoice",
1474
+ * html: "<p>Attached.</p>",
1475
+ * tags: [{ name: "category", value: "billing" }],
1476
+ * metadata: { invoice_id: "inv_123" },
1477
+ * track_clicks: false,
1478
+ * },
1479
+ * { idempotencyKey: "invoice-march/cust_1" },
1480
+ * );
1481
+ *
1482
+ * @example Branch on the typed error hierarchy
1483
+ * // bird:snippet:start email.errors
1484
+ * import { BirdRateLimitError, BirdValidationError, BirdAPIError } from "@messagebird/sdk";
1485
+ *
1486
+ * try {
1487
+ * await bird.email.send({
1488
+ * from: "onboarding@messagebird.dev",
1489
+ * to: ["delivered@messagebird.dev"],
1490
+ * subject: "Hello from Bird",
1491
+ * html: "<p>My first Bird email.</p>",
1492
+ * });
1493
+ * } catch (err) {
1494
+ * if (err instanceof BirdRateLimitError) console.log(`rate limited — retry in ${err.retryAfter}s`);
1495
+ * else if (err instanceof BirdValidationError) console.error(err.details);
1496
+ * else if (err instanceof BirdAPIError) console.error(err.code, err.requestId);
1497
+ * else throw err;
1498
+ * }
1499
+ * // bird:snippet:end email.errors
1500
+ *
1501
+ * @example Errors as values with `.safe()`
1502
+ * // bird:snippet:start email.safe
1503
+ * const { data, error } = await bird.email
1504
+ * .send({
1505
+ * from: "onboarding@messagebird.dev",
1506
+ * to: ["delivered@messagebird.dev"],
1507
+ * subject: "Hello from Bird",
1508
+ * html: "<p>My first Bird email.</p>",
1509
+ * })
1510
+ * .safe();
1511
+ * if (error) console.error(error.message);
1512
+ * else console.log(data.id);
1513
+ * // bird:snippet:end email.safe
1514
+ */
1515
+ send(params: EmailSend<D>, options?: RequestOptions$1): APIPromise<EmailMessage>;
1516
+ /**
1517
+ * Fetch a message with aggregate delivery status.
1518
+ *
1519
+ * @example
1520
+ * // bird:snippet:start email.get
1521
+ * const msg = await bird.email.get("em_abc123");
1522
+ * msg.status; // "accepted" | "processed" | "delivered" | "bounced" | …
1523
+ * msg.delivered_count;
1524
+ * msg.bounced_count;
1525
+ * // bird:snippet:end email.get
1526
+ */
1527
+ get(messageId: string, options?: RequestOptions$1): APIPromise<EmailMessage>;
1528
+ /**
1529
+ * List messages, newest first. `await` resolves the first page; `for await`
1530
+ * walks every message across all pages.
1531
+ *
1532
+ * @example Iterate every message, or take one page
1533
+ * // bird:snippet:start email.list.paginate
1534
+ * // bird:snippet:start email.list.iterate
1535
+ * for await (const message of bird.email.list({ status: "bounced" })) {
1536
+ * console.log(message.id);
1537
+ * }
1538
+ * // bird:snippet:end email.list.iterate
1539
+ * const page = await bird.email.list({ limit: 50 }); // page.data, page.next_cursor
1540
+ * // bird:snippet:end email.list.paginate
1541
+ */
1542
+ list(query?: EmailListQuery, options?: RequestOptions$1): PaginatedPromise<EmailMessage>;
1543
+ }
1544
+
1545
+ /** A verified webhook event — discriminated on `type` (ADR-0028 wire contract). */
1546
+ type BirdWebhookEvent = WebhookEvent;
1547
+ /** Inbound request headers, as a `Headers` object or a plain record. */
1548
+ type WebhookHeaders = Headers | Record<string, string>;
1549
+ /** Client-level webhooks config (`new BirdClient({ webhooks: { secret } })`). */
1550
+ interface WebhookOptions {
1551
+ /** Signing secret used by `unwrap`; a per-call `secret` overrides it. */
1552
+ secret?: string;
1553
+ }
1554
+ declare class WebhooksResource {
1555
+ #private;
1556
+ constructor(config?: WebhookOptions);
1557
+ /**
1558
+ * Verify a webhook delivery and return the typed event.
1559
+ *
1560
+ * **Pass the raw request body**, exactly as received — do NOT parse it first.
1561
+ * The Standard Webhooks signature is computed over the raw bytes, so parsing
1562
+ * and re-serializing before verifying is the classic webhook bug.
1563
+ *
1564
+ * The secret comes from `webhooks.secret` on the client; pass `{ secret }` to
1565
+ * override per call. Throws {@link BirdWebhookVerificationError} on a bad
1566
+ * signature, a stale timestamp, or missing/malformed headers. Unknown event
1567
+ * types are returned as-is (handle them in a `default` case) so a newer server
1568
+ * event can't break an older SDK.
1569
+ *
1570
+ * @example Verify and dispatch — pass the raw request body, never the parsed JSON
1571
+ * // new BirdClient({ apiKey, webhooks: { secret } })
1572
+ * try {
1573
+ * const event = bird.webhooks.unwrap(rawBody, req.headers);
1574
+ * switch (event.type) {
1575
+ * case "email.delivered":
1576
+ * markDelivered(event.email_id, event.recipient); // narrowed; fields are flat
1577
+ * break;
1578
+ * case "email.bounced":
1579
+ * case "email.complained":
1580
+ * suppress(event.recipient);
1581
+ * break;
1582
+ * default: // unknown future event types — an older SDK won't break on a new one
1583
+ * }
1584
+ * } catch (err) {
1585
+ * if (err instanceof BirdWebhookVerificationError) {
1586
+ * // reject with 400 — bad signature, stale timestamp, or missing/malformed headers
1587
+ * } else throw err;
1588
+ * }
1589
+ */
1590
+ unwrap(payload: string, headers: WebhookHeaders, options?: WebhookOptions): BirdWebhookEvent;
1591
+ }
1592
+
1593
+ interface BirdClientOptions {
1594
+ apiKey: string;
1595
+ /** Explicit base URL; overrides region resolution. For local/self-hosted use. */
1596
+ baseUrl?: string;
1597
+ /** Region override (e.g. `"eu1"`); the API key prefix is used by default. */
1598
+ region?: string;
1599
+ /** Per-attempt timeout in ms. Default 60_000. */
1600
+ timeout?: number;
1601
+ /** Max retry attempts on retryable failures (429, 5xx, network). Default 2. */
1602
+ maxRetries?: number;
1603
+ /** Custom fetch — testing, proxying, edge-runtime adapters. Default global fetch. */
1604
+ fetch?: typeof fetch;
1605
+ /** Headers added to every request. SDK-internal headers win on conflict. */
1606
+ defaultHeaders?: Record<string, string>;
1607
+ /**
1608
+ * Email channel defaults. Any field set here may be omitted in
1609
+ * `bird.email.send` (the type enforces this); the per-send value wins.
1610
+ */
1611
+ email?: EmailChannelDefaults;
1612
+ /** Webhooks config — `secret` is the default used by `bird.webhooks.unwrap`. */
1613
+ webhooks?: WebhookOptions;
1614
+ }
1615
+ /** A raw request for the `bird.request` escape hatch. */
1616
+ interface BirdRequest {
1617
+ method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
1618
+ /**
1619
+ * Absolute path on the API host, e.g. `/v1/email/domains`; must start
1620
+ * with a single `/`.
1621
+ */
1622
+ path: string;
1623
+ query?: Record<string, string | number | boolean | undefined>;
1624
+ /** JSON request body. */
1625
+ body?: unknown;
1626
+ headers?: Record<string, string>;
1627
+ }
1628
+ type EmailDefaultsOf<O> = O extends {
1629
+ email: infer E extends EmailChannelDefaults;
1630
+ } ? E : undefined;
1631
+ /**
1632
+ * The Bird API client. Construct it with an API key; the region is taken from
1633
+ * the key's prefix (`bk_{region}_…`) — pass `baseUrl` or `region` to override.
1634
+ *
1635
+ * @example Construct and send
1636
+ * const bird = new BirdClient({ apiKey: process.env.BIRD_API_KEY! });
1637
+ * const msg = await bird.email.send({
1638
+ * from: "hello@acme.com",
1639
+ * to: ["customer@example.com"],
1640
+ * subject: "Welcome aboard",
1641
+ * html: "<h1>Hi there 👋</h1>",
1642
+ * });
1643
+ * console.log(msg.id);
1644
+ *
1645
+ * @example Channel defaults — set common send fields once; a per-send value always wins
1646
+ * const bird = new BirdClient({
1647
+ * apiKey: process.env.BIRD_API_KEY!,
1648
+ * email: { from: "hello@acme.com", category: "transactional" },
1649
+ * });
1650
+ * // `from` and `category` are filled from the defaults; both stay optional in `send`.
1651
+ * await bird.email.send({ to: ["customer@example.com"], subject: "Hi", html: "<p>hi</p>" });
1652
+ *
1653
+ * @example All client options
1654
+ * // bird:snippet:start client.options
1655
+ * const bird = new BirdClient({
1656
+ * apiKey: process.env.BIRD_API_KEY!,
1657
+ * region: "eu1", // optional — override the region from the key prefix
1658
+ * baseUrl: "http://localhost:8080", // optional — overrides region entirely (local/self-hosted)
1659
+ * timeout: 60_000, // per-attempt timeout in ms (default 60_000)
1660
+ * maxRetries: 2, // retry budget for transient failures (default 2)
1661
+ * });
1662
+ * // bird:snippet:end client.options
1663
+ */
1664
+ declare class BirdClient<const O extends BirdClientOptions = BirdClientOptions> {
1665
+ #private;
1666
+ protected readonly core: BirdHTTPClient;
1667
+ /** The email channel — `bird.email.send(...)`, `.get(...)`, `.list(...)`. */
1668
+ readonly email: EmailResource<EmailDefaultsOf<O>>;
1669
+ /** Webhooks — `bird.webhooks.unwrap(payload, headers)` verifies an inbound delivery. */
1670
+ readonly webhooks: WebhooksResource;
1671
+ constructor(options: O);
1672
+ /**
1673
+ * Escape hatch for endpoints the typed resources don't cover. Runs the full
1674
+ * lifecycle (auth, retries, idempotency, error mapping); you supply the
1675
+ * response type. Prefer a typed resource method where one exists.
1676
+ *
1677
+ * @throws {TypeError} if `req.path` does not start with exactly one `/` or
1678
+ * resolves to a different origin than the configured Bird API base URL.
1679
+ *
1680
+ * @example Reach an endpoint outside the curated surface — you supply the response type
1681
+ * type Suppressions = { data: Array<{ recipient: string }> };
1682
+ * const suppressions = await bird.request<Suppressions>({ method: "GET", path: "/v1/email/suppressions" });
1683
+ * console.log(suppressions.data.length);
1684
+ */
1685
+ request<T = unknown>(req: BirdRequest, options?: RequestOptions$1): APIPromise<T>;
1686
+ }
1687
+
1688
+ /** Extracts the region code from a `bk_{region}_{token}` key, or undefined. */
1689
+ declare function regionFromApiKey(apiKey: string): string | undefined;
1690
+ declare function baseUrlForRegion(region: string): string;
1691
+
1692
+ export { type APIPromise, BirdAPIError, BirdAuthError, BirdBadRequestError, BirdBillingError, BirdClient, type BirdClientOptions, BirdConflictError, BirdConnectionError, BirdError, BirdInternalError, BirdMisdirectedError, BirdNotFoundError, BirdNotImplementedError, BirdPayloadTooLargeError, BirdPermissionError, BirdPreconditionError, BirdRateLimitError, type BirdRequest, type BirdResponse, BirdServiceUnavailableError, BirdTimeoutError, BirdValidationError, type BirdWebhookEvent, BirdWebhookVerificationError, type CursorPage, type EmailChannelDefaults, type EmailListQuery, type EmailMessage, type EmailSendParams, type ErrorDetail, type PaginatedPromise, type RequestOptions$1 as RequestOptions, type SafeResult, type WebhookHeaders, type WebhookOptions, baseUrlForRegion, regionFromApiKey };