@messagebird/sdk 0.27.0 → 0.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -97,14 +97,34 @@ interface ErrorDetail {
97
97
  /** What is wrong with this field. */
98
98
  message: string;
99
99
  }
100
- /** One recovery step: an operation to call to resolve the error. */
101
- interface ErrorNextAction {
102
- /** operationId of the follow-up operation that resolves this error. */
103
- operation: string;
104
- /** Short human-readable label for the recovery step. */
105
- description?: string;
106
- /** Permission scope the recovery operation requires, when it is scoped. */
107
- scope?: string;
100
+ /**
101
+ * One recovery step the server suggests. Read `kind` before `operation`: only an
102
+ * `operation` step carries one.
103
+ */
104
+ interface NextAction {
105
+ /**
106
+ * What to do about this step: `operation` calls the operation named in
107
+ * `operation` and reads again, `external` acts somewhere this API does not
108
+ * reach, `wait` reads again later, `terminal` means nothing resolves this so
109
+ * stop retrying. A value this SDK version does not know is display-only: show
110
+ * `description` and offer no action.
111
+ */
112
+ kind: string;
113
+ /** Short human-readable label for the step, suitable for display. */
114
+ description: string;
115
+ /** operationId to call. Present only when `kind` is `operation`. */
116
+ operation?: string;
117
+ /**
118
+ * Parameters that address `operation`, by name — every parameter the call
119
+ * needs, so it can be made from this step alone. A request body, when the
120
+ * operation takes one, is described by the operation and never appears here.
121
+ */
122
+ params?: Record<string, string>;
123
+ /**
124
+ * A URL to open. Present only when `kind` is `external`, and only when the step
125
+ * has one; an external step with nothing to open is normal.
126
+ */
127
+ url?: string;
108
128
  }
109
129
  /** One verification requirement blocking the action, with the flow that resolves it. */
110
130
  interface UnmetGate {
@@ -137,8 +157,8 @@ interface BirdAPIErrorFields {
137
157
  vendorCode?: string;
138
158
  /** Human recovery line for this error, when a recovery is known. */
139
159
  remediation?: string;
140
- /** Operations that resolve this error, in the order to try them. */
141
- next?: ErrorNextAction[];
160
+ /** Recovery steps for this error, in the order to take them. */
161
+ next?: NextAction[];
142
162
  /** Verification requirements blocking this action, when it is blocked pending verification. */
143
163
  unmetGates?: UnmetGate[];
144
164
  }
@@ -153,7 +173,7 @@ declare class BirdAPIError extends BirdError {
153
173
  readonly param?: string;
154
174
  readonly vendorCode?: string;
155
175
  readonly remediation?: string;
156
- readonly next?: ErrorNextAction[];
176
+ readonly next?: NextAction[];
157
177
  readonly unmetGates?: UnmetGate[];
158
178
  constructor(fields: BirdAPIErrorFields);
159
179
  }
@@ -332,31 +352,31 @@ type VoiceMediaQuality = {
332
352
  *
333
353
  * Most of them you can fix yourself:
334
354
  *
335
- * - `source_not_allowed`: the call came from an IP address that is not in the
355
+ * - `source_not_allowed`: The call came from an IP address that is not in the
336
356
  * trunk's allowed-address list. Add the address your PBX sends from.
337
- * - `caller_id_not_verified`: the number in the `From` header is not a verified
357
+ * - `caller_id_not_verified`: The number in the `From` header is not a verified
338
358
  * caller ID for this workspace. Verify it, or present a number you have
339
359
  * already verified.
340
- * - `destination_not_enabled`: you have not turned on calling to this
360
+ * - `destination_not_enabled`: You have not turned on calling to this
341
361
  * destination country. Enable it in your voice destination settings.
342
- * - `insufficient_balance`: your wallet did not cover the call. Top up, or turn
362
+ * - `insufficient_balance`: Your wallet did not cover the call. Top up, or turn
343
363
  * on automatic top-ups.
344
- * - `daily_spend_exceeded`: the call would have passed your organization's daily
364
+ * - `daily_spend_exceeded`: The call would have passed your organization's daily
345
365
  * voice spend limit. The limit resets at the start of the next UTC day.
346
- * - `concurrent_calls_exceeded`: you already have as many calls in progress as
366
+ * - `concurrent_calls_exceeded`: You already have as many calls in progress as
347
367
  * your account allows. Wait for one to end, or ask support to raise the limit.
348
- * - `calls_per_second_exceeded`: you placed calls faster than your account
368
+ * - `calls_per_second_exceeded`: You placed calls faster than your account
349
369
  * allows. Slow the rate you dial at, then retry.
350
370
  *
351
371
  * The rest need Bird to act, so contact support and quote the call `id`:
352
372
  *
353
- * - `routing_not_configured`: no dial plan is attached to this trunk yet.
373
+ * - `routing_not_configured`: No dial plan is attached to this trunk yet.
354
374
  * Expected on a trunk that was just created.
355
- * - `no_route_found`: a dial plan is attached, but no rule in it covers this
375
+ * - `no_route_found`: A dial plan is attached, but no rule in it covers this
356
376
  * destination.
357
- * - `destination_blocked`: the destination is blocked by Bird's routing
377
+ * - `destination_blocked`: The destination is blocked by our routing
358
378
  * configuration.
359
- * - `call_not_permitted`: the call could not be priced for your account.
379
+ * - `call_not_permitted`: The call could not be priced for your account.
360
380
  *
361
381
  */
362
382
  type VoiceCallRejectionReason = "source_not_allowed" | "caller_id_not_verified" | "routing_not_configured" | "no_route_found" | "destination_blocked" | "destination_not_enabled" | "insufficient_balance" | "daily_spend_exceeded" | "concurrent_calls_exceeded" | "calls_per_second_exceeded" | "call_not_permitted";
@@ -786,7 +806,7 @@ type EventVerifyVerificationVerifiedData = EventVerifyBase & {
786
806
  /**
787
807
  * The channel a passcode is delivered over. Open enum — new channels may be added over time, so treat any unrecognized value as a future channel rather than an error.
788
808
  */
789
- type VerificationChannel$1 = "email" | "sms" | "whatsapp" | (string & {});
809
+ type VerificationChannel$1 = "email" | "sms" | "whatsapp" | "telegram" | (string & {});
790
810
  /**
791
811
  * The recipient to verify. Provide an `email`, a `phone_number`, or both; at least one is required. The addresses also identify the verification: a check must supply exactly the set used on the create call, so a verification created with both addresses is not found by either one alone.
792
812
  *
@@ -962,11 +982,11 @@ type EventVerifyAttemptDeliveredData = EventVerifyBase & {
962
982
  */
963
983
  address: string;
964
984
  /**
965
- * Carrier that delivered the message, when the carrier network reports it. Always null for email and WhatsApp.
985
+ * Carrier that delivered the message, when the carrier network reports it. Always null for email, WhatsApp, and Telegram.
966
986
  */
967
987
  carrier: string | null;
968
988
  /**
969
- * Mobile country code and mobile network code of the delivering carrier, when reported. Always null for email and WhatsApp.
989
+ * Mobile country code and mobile network code of the delivering carrier, when reported. Always null for email, WhatsApp, and Telegram.
970
990
  */
971
991
  mcc_mnc: string | null;
972
992
  /**
@@ -1693,7 +1713,17 @@ type EventEmailScheduled = {
1693
1713
  };
1694
1714
  /**
1695
1715
  * Why an email was rejected before delivery.
1696
- * `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. `domain_unverified` means the sending domain was not verified. `quota_exceeded` means the organization's send quota was reached. `recipient_not_allowed` means a recipient was not permitted for this send (for shared onboarding-domain sends, recipients must be verified workspace members).
1716
+ *
1717
+ * - `recipient_suppressed`: The recipient is on the workspace suppression list, so
1718
+ * delivery was never attempted.
1719
+ * - `transmission_failed`: The message could not be transmitted for delivery.
1720
+ * - `generation_failure`: The message could not be built for delivery (template or
1721
+ * content issue).
1722
+ * - `policy_rejection`: The message was refused by sending policy.
1723
+ * - `domain_unverified`: The sending domain was not verified.
1724
+ * - `quota_exceeded`: The organization's send quota was reached.
1725
+ * - `recipient_not_allowed`: A recipient was not permitted for this send (for shared
1726
+ * onboarding-domain sends, recipients must be verified workspace members).
1697
1727
  *
1698
1728
  */
1699
1729
  type EmailRejectionReason = "recipient_suppressed" | "transmission_failed" | "generation_failure" | "policy_rejection" | "domain_unverified" | "quota_exceeded" | "recipient_not_allowed";
@@ -1722,7 +1752,7 @@ type EventEmailRejected = {
1722
1752
  */
1723
1753
  type EventEmailReceivedData = {
1724
1754
  /**
1725
- * ID of the received email. Use it with GET /v1/email/inbound-messages/{id} to fetch the body, raw content, and attachments.
1755
+ * ID of the received email. Fetch its parsed metadata with `GET /v1/email/inbound-messages/{id}`, and its content from that message's `/body`, `/raw`, and `/attachments` sub-resources.
1726
1756
  */
1727
1757
  inbound_message_id: InboundEmailMessageId;
1728
1758
  /**
@@ -1767,12 +1797,12 @@ type EventEmailReceivedData = {
1767
1797
  */
1768
1798
  dmarc_pass?: boolean | null;
1769
1799
  /**
1770
- * Spam score for the message. Always null at present; reserved for a future content-scoring capability.
1800
+ * Spam score carried on the received message, or null when it carries no score.
1771
1801
  */
1772
1802
  spam_score?: number | null;
1773
1803
  };
1774
1804
  /**
1775
- * Bird received and parsed an inbound email. The payload carries the message's identifiers, sender and recipients, subject, threading reference, and authentication results enough to route and triage without a fetch. Fetch the body, full headers, and attachments with GET /v1/email/inbound-messages/{id}.
1805
+ * Bird received and parsed an inbound email. The payload carries the message's identifiers, sender and recipients, subject, threading reference, and authentication results, which is enough to route and triage without a fetch. Content is fetched separately: the parsed body with `GET /v1/email/inbound-messages/{id}/body`, the original MIME with `GET /v1/email/inbound-messages/{id}/raw`, and attachment bytes with `GET /v1/email/inbound-messages/{id}/attachments/{attachment_id}`.
1776
1806
  */
1777
1807
  type EventEmailReceived = {
1778
1808
  /**
@@ -1827,7 +1857,13 @@ type EventEmailOutOfBandBounceData = EventEmailBase & {
1827
1857
  sending_ip: string | null;
1828
1858
  };
1829
1859
  /**
1830
- * 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.
1860
+ * Bounce classification.
1861
+ *
1862
+ * - `hard`: A permanent failure, such as an invalid address or a domain that does not exist.
1863
+ * - `soft`: A transient failure, such as a full mailbox or a server that is temporarily unavailable.
1864
+ * - `block`: The receiving mail server refused the sending IP on reputation grounds.
1865
+ * - `admin`: An administrative refusal, such as relaying denied or a blocklisted domain.
1866
+ * - `undetermined`: The receiving server's response was ambiguous.
1831
1867
  *
1832
1868
  */
1833
1869
  type EmailBounceType = "hard" | "soft" | "undetermined" | "admin" | "block";
@@ -2261,25 +2297,35 @@ type EmailMailboxLabel = {
2261
2297
  */
2262
2298
  readonly name: string;
2263
2299
  /**
2264
- * `system` labels are built in and carry state — the placements `inbox`, `archive`, `spam`, `blocked`, and `sent`, plus `trash` and `unread`. `custom` labels are the workspace's own tags.
2300
+ * `system` labels are the built-in placements a message can be in:
2301
+ *
2302
+ * - Inbox.
2303
+ * - Archive.
2304
+ * - Spam.
2305
+ * - Blocked.
2306
+ * - Sent.
2307
+ * - Trash.
2308
+ * - Unread.
2309
+ *
2310
+ * `custom` labels are the workspace's own tags.
2265
2311
  */
2266
2312
  readonly type: "system" | "custom";
2267
2313
  };
2268
2314
  /**
2269
- * A new message sent from a mailbox, starting a new conversation. Mirrors the plain send request minus `from` the mailbox is the sender identity and minus `scheduled_at` (mailbox sends are immediate). Bird mints the RFC 5322 Message-ID so replies thread back to this conversation. At least one of `html` or `text` must be provided.
2315
+ * A new message sent from a mailbox, starting a new conversation. Mirrors the plain send request without `from`, because the mailbox is who the message comes from, and without `scheduled_at`, because a mailbox sends immediately. We set the RFC 5322 Message-ID so replies thread back into this conversation. At least one of `html` or `text` must be provided.
2270
2316
  *
2271
2317
  */
2272
2318
  type EmailMailboxComposeRequest = {
2273
2319
  /**
2274
- * 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.
2320
+ * Primary recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@acme.com>`), or an object with an optional display name.
2275
2321
  */
2276
2322
  to: Array<EmailAddressInput>;
2277
2323
  /**
2278
- * 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.
2324
+ * CC recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@acme.com>`), or an object with an optional display name.
2279
2325
  */
2280
2326
  cc?: Array<EmailAddressInput>;
2281
2327
  /**
2282
- * 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.
2328
+ * BCC recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@acme.com>`), or an object with an optional display name.
2283
2329
  */
2284
2330
  bcc?: Array<EmailAddressInput>;
2285
2331
  /**
@@ -2300,7 +2346,7 @@ type EmailMailboxComposeRequest = {
2300
2346
  */
2301
2347
  reply_to?: Array<EmailAddressInput>;
2302
2348
  /**
2303
- * File attachments. The send is rejected when the estimated generated message size exceeds 20 MB (bodies plus all attachments after base64 encoding). Attachment metadata endures on the message's `attachment_manifest`; the bytes are downloadable for 30 days.
2349
+ * File attachments. The send is rejected when the estimated generated message size exceeds 20 MB (bodies plus all attachments after base64 encoding). Keep total raw attachment content at or below 15 MB for reliable headroom. Attachment metadata stays on the message's `attachment_manifest`, and the bytes are downloadable for 30 days.
2304
2350
  *
2305
2351
  */
2306
2352
  attachments?: Array<EmailAttachment>;
@@ -2319,41 +2365,40 @@ type EmailMailboxComposeRequest = {
2319
2365
  category?: EmailMessageCategory;
2320
2366
  };
2321
2367
  /**
2322
- * Content classification. Controls suppression policy: `marketing` blocks on all suppression reasons; `transactional` allows delivery through complaint and unsubscribe suppressions, for receipts, password resets, and similar operational mail.
2368
+ * Content classification, which controls suppression policy:
2369
+ *
2370
+ * - `marketing`: Blocks on all suppression reasons.
2371
+ * - `transactional`: Allows delivery through complaint and unsubscribe suppressions, for receipts, password resets, and similar operational mail.
2323
2372
  *
2324
2373
  */
2325
2374
  type EmailMessageCategory = "marketing" | "transactional";
2326
2375
  /**
2327
- * 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.
2328
- * Inline images for `<img src="cid:..."/>` references in the HTML body use the `content_id` field together with `content`.
2329
- * Bird enforces a **20 MB estimated generated message size** cap. The estimate is the HTML and text body plus all attachments and inline images measured after base64 encoding. This is not a raw file-size cap. As a rule of thumb, keep total raw attachment content at or below **15 MB** so the generated message has enough room after encoding and MIME wrapping.
2330
- * Recipient-side delivery reality: downstream limits vary by product and tenant/server policy. Gmail personal and Outlook.com document 25 MB attachment limits. Exchange Online defaults to 35 MB send / 36 MB receive, but admins can configure limits; on-prem Exchange Server organizational defaults are 10 MB. Sends close to Bird's 20 MB generated-message cap may be accepted by Bird but bounce at the recipient's mail server.
2331
- * Batch sends can include attachments on individual message objects. Each message still has the 20 MB estimated generated-size cap, and the serialized JSON request body for the whole batch has a hard 20 MB cap. Certain executable / script content types are rejected at validation time.
2376
+ * A file attached to an email. Put the file's bytes in `content`, base64-encoded, and give it the `filename` the recipient will see.
2377
+ *
2378
+ * To show an image inline, so that `<img src="cid:..."/>` in your HTML body picks it up, set `content_id` alongside `content`.
2379
+ *
2380
+ * Each message can be at most **20 MB** once it has been generated. That figure covers the HTML body, the text body, and every attachment and inline image, all measured after base64 encoding rather than as raw files. Base64 and MIME wrapping add roughly a third, so keep the raw content of your attachments at or below **15 MB** to stay under the cap.
2381
+ *
2382
+ * A message we accept can still bounce at the other end, because every mail provider sets its own limit. Gmail and Outlook.com both publish a 25 MB limit. Exchange Online defaults to 35 MB for sending and 36 MB for receiving, though an administrator can change both, and on-premise Exchange Server defaults to 10 MB. So a message close to 20 MB is worth testing against the providers your recipients actually use.
2383
+ *
2384
+ * A batch send can attach files to each message in the batch. Every message is still held to the same 20 MB, and the whole request body is capped at 20 MB as well. Executable and script content types are refused when the request is validated.
2332
2385
  *
2333
2386
  */
2334
2387
  type EmailAttachment = {
2335
2388
  /**
2336
- * Filename shown to the recipient. Required.
2389
+ * The name the recipient sees on the attachment.
2337
2390
  */
2338
2391
  filename: string;
2339
2392
  /**
2340
- * Base64-encoded attachment bytes. Required. Counts toward the 20 MB estimated generated message-size cap after encoding and MIME wrapping.
2341
- *
2393
+ * The file's bytes, base64-encoded. What you send here counts toward the message's 20 MB limit after encoding and MIME wrapping, not at its raw size.
2342
2394
  */
2343
2395
  content: string;
2344
2396
  /**
2345
- * 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 `UnsupportedEmailFeature` 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 toward the 20 MB estimated generated message-size cap after encoding and MIME wrapping.
2346
- *
2347
- */
2348
- path?: string;
2349
- /**
2350
- * MIME type. Inferred from `filename` extension when omitted. Used to enforce the blocklist of disallowed executable / script types.
2351
- *
2397
+ * The file's MIME type. Leave it out and we work it out from the extension on `filename`. This is what we check against the list of executable and script types we refuse.
2352
2398
  */
2353
2399
  content_type?: string;
2354
2400
  /**
2355
- * 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.
2356
- *
2401
+ * An RFC 2392 Content-ID for the file. Set it and the attachment is shown inline, so your HTML body can point at it with `<img src="cid:{content_id}"/>`. Leave it out and the file arrives as an ordinary attachment the recipient downloads.
2357
2402
  */
2358
2403
  content_id?: string;
2359
2404
  };
@@ -2371,7 +2416,7 @@ type EmailAddress = {
2371
2416
  name?: string;
2372
2417
  };
2373
2418
  /**
2374
- * 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.
2419
+ * A sender or recipient address. Accepts a plain email string (`jane@acme.com`), an RFC 5322 mailbox string with an embedded display name (`Jane Doe <jane@acme.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.
2375
2420
  *
2376
2421
  */
2377
2422
  type EmailAddressInput = string | EmailAddress;
@@ -2406,7 +2451,7 @@ type EmailThreadMessageReplyRequest = {
2406
2451
  };
2407
2452
  category?: EmailMessageCategory;
2408
2453
  /**
2409
- * File attachments to include with the reply. The send is rejected when the estimated generated message size exceeds 20 MB (bodies plus all attachments after base64 encoding). Keep total raw attachment content at or below 15 MB for reliable headroom. Attachment metadata endures on the message's `attachment_manifest`; the bytes are downloadable for 30 days.
2454
+ * File attachments to include with the reply. The send is rejected when the estimated generated message size exceeds 20 MB (bodies plus all attachments after base64 encoding). Keep total raw attachment content at or below 15 MB for reliable headroom. Attachment metadata stays on the message's `attachment_manifest`, and the bytes are downloadable for 30 days.
2410
2455
  *
2411
2456
  */
2412
2457
  attachments?: Array<EmailAttachment>;
@@ -2418,7 +2463,7 @@ type EmailThreadMessageAttachmentList = {
2418
2463
  data: Array<EmailThreadMessageAttachment>;
2419
2464
  };
2420
2465
  /**
2421
- * Attachment metadata on a conversation message. The metadata remains readable for the mailbox's retention period; the attachment bytes are downloadable for 30 days after the message occurred.
2466
+ * Attachment metadata on a conversation message. The metadata stays readable for the mailbox's retention tier. The attachment bytes are downloadable for 30 days after the message occurred.
2422
2467
  *
2423
2468
  */
2424
2469
  type EmailThreadMessageAttachment = {
@@ -2440,7 +2485,7 @@ type EmailThreadMessageAttachment = {
2440
2485
  readonly size: number;
2441
2486
  };
2442
2487
  /**
2443
- * The original rendered body of a conversation message. Available for 30 days after the message occurred; after that the endpoint returns `410 Gone` while the message's extracted text remains readable on the message itself.
2488
+ * The original rendered body of a conversation message. Available for 30 days after the message occurred. After that, the endpoint returns `410 Gone`, but the message's extracted text stays readable on the message itself.
2444
2489
  *
2445
2490
  */
2446
2491
  type EmailThreadMessageBody = {
@@ -2455,7 +2500,7 @@ type EmailThreadMessageBody = {
2455
2500
  };
2456
2501
  type ContactId = string;
2457
2502
  /**
2458
- * Label changes to apply. Labels in `add` are applied and labels in `remove` are taken off; other labels are left untouched. Adding a label that is already present, or removing one that is not, has no effect. System labels express state changes: on a conversation, adding `spam` files it as spam, adding `archive` files it away without deleting it, adding `inbox` (or removing `spam` or `archive`) returns it to the inbox, and removing `unread` marks all retained received messages as read in one call; on a message, adding or removing `unread` flips read state, and adding or removing `trash` moves it to or out of the trash. Changes that contradict this model are rejected: adding more than one placement label in one request, adding `blocked` (blocking a sender is a receive-rule decision), removing `inbox` without adding a destination, adding `trash` or `unread` to a conversation (removing `unread` is the mark-all-read shortcut; `trash` uses the DELETE verb), placement labels on a message (move its conversation instead), and `unread` on a sent message. Custom labels are 1-64 characters with no commas, control characters, or leading or trailing whitespace. System label names and a small reserved set (`all`, `archived`, `deleted`, `draft`, `drafts`, `flagged`, `important`, `junk`, `muted`, `none`, `outbox`, `pinned`, `read`, `scheduled`, `snoozed`, `starred`) cannot be used as custom labels, in any casing. A conversation or message carries at most 20 labels, system labels included.
2503
+ * Label changes to apply. Labels in `add` are applied and labels in `remove` are taken off; other labels are left untouched. Adding a label that is already present, or removing one that is not, has no effect. System labels express state changes: on a conversation, adding `spam` files it as spam, adding `archive` files it away without deleting it, adding `inbox` (or removing `spam`, `blocked`, or `archive`) returns it to the inbox, and removing `unread` marks all retained received messages as read in one call; on a message, adding or removing `unread` flips read state, and adding or removing `trash` moves it to or out of the trash. Changes that contradict this model are rejected: adding more than one placement label in one request, adding `blocked` (blocking a sender is a receive-rule decision), removing `inbox` without adding a destination, adding `trash` or `unread` to a conversation (removing `unread` is the mark-all-read shortcut; `trash` uses the DELETE verb), placement labels on a message (move its conversation instead), and `unread` on a sent message. Custom labels are 1-64 characters with no commas, control characters, or leading or trailing whitespace. System label names and a small reserved set (`all`, `archived`, `deleted`, `draft`, `drafts`, `flagged`, `important`, `junk`, `muted`, `none`, `outbox`, `pinned`, `read`, `scheduled`, `snoozed`, `starred`) cannot be used as custom labels, in any casing. A conversation or message has at most 20 labels, system labels included.
2459
2504
  *
2460
2505
  */
2461
2506
  type EmailLabelsUpdate = {
@@ -2469,7 +2514,7 @@ type EmailLabelsUpdate = {
2469
2514
  remove?: Array<string>;
2470
2515
  };
2471
2516
  /**
2472
- * Link to the message's entry in the received-message or sent-message log, which carries delivery analytics such as per-recipient events. Log entries expire 30 days after the message occurred.
2517
+ * Link to the message's entry in the received-message or sent-message log, which has delivery analytics such as per-recipient events. Log entries expire 30 days after the message occurred.
2473
2518
  *
2474
2519
  */
2475
2520
  type EmailThreadMessageSource = {
@@ -2483,7 +2528,7 @@ type EmailThreadMessageSource = {
2483
2528
  readonly available_until: string;
2484
2529
  };
2485
2530
  /**
2486
- * One recipient's terminal delivery outcome on a sent conversation message, folded into the message's durable memory when the outcome becomes known.
2531
+ * One recipient's terminal delivery outcome on a sent conversation message, recorded once the outcome becomes known.
2487
2532
  *
2488
2533
  */
2489
2534
  type EmailThreadMessageRecipient = {
@@ -2497,21 +2542,21 @@ type EmailThreadMessageRecipient = {
2497
2542
  readonly status: "delivered" | "failed";
2498
2543
  };
2499
2544
  /**
2500
- * A message in a mailbox conversation, either direction. Message metadata and extracted text remain readable for the mailbox's retention period; the original rendered source (HTML body, raw MIME, attachment bytes) is available through the body, raw, and attachment endpoints for 30 days after the message occurred.
2545
+ * A message in a mailbox conversation, either direction. Message metadata and extracted text stay readable for the mailbox's retention tier. The original rendered source (HTML body, raw MIME, attachment bytes) is available through the body, raw, and attachment endpoints for 30 days after the message occurred.
2501
2546
  *
2502
2547
  */
2503
2548
  type EmailThreadMessage = {
2504
2549
  /**
2505
- * Message ID. Received messages carry a `rem_` ID, sent messages an `em_` ID the same IDs used by the received-message and sent-message logs.
2550
+ * Message ID. Received messages have a `rem_` ID, sent messages an `em_` ID: the same IDs used by the received-message and sent-message logs.
2506
2551
  *
2507
2552
  */
2508
2553
  readonly id: string;
2509
2554
  /**
2510
- * Direction of the message `inbound` for a received message, `outbound` for a sent one.
2555
+ * Which way the message went. `inbound` means you received it, `outbound` means you sent it.
2511
2556
  */
2512
2557
  readonly direction: "inbound" | "outbound";
2513
2558
  /**
2514
- * Channel this message was carried on. Always `email`.
2559
+ * Channel this message lives on. Always `email`.
2515
2560
  */
2516
2561
  readonly channel: string;
2517
2562
  /**
@@ -2544,47 +2589,61 @@ type EmailThreadMessage = {
2544
2589
  */
2545
2590
  readonly preview: string | null;
2546
2591
  /**
2547
- * Plain-text content of the message with quoted history stripped readable for the mailbox's full retention period, both directions. Always present when fetching a single message; on list endpoints it is included only when the request sets `include=extracted_text`. Null when no text could be extracted.
2592
+ * Plain-text content of the message with quoted history stripped. Readable for the mailbox's full retention tier, in both directions. Always present when fetching a single message. On list endpoints it is included only when the request sets `include=extracted_text`. Null when no text could be extracted.
2548
2593
  *
2549
2594
  */
2550
2595
  readonly extracted_text?: string | null;
2551
2596
  /**
2552
- * Labels on this message. System labels carry its state: a received message holds exactly one placement label — `inbox` for accepted mail, `archive` when its conversation was filed away, `spam` (failed sender authentication), or `blocked` (rejected by the mailbox's receive policy or rules) — plus `unread` until it is read. `trash` marks a message in the trash, either direction. Custom labels share the same list; a message carries at most 20.
2597
+ * Labels on this message. A received message always has exactly one placement label:
2598
+ *
2599
+ * - `inbox`: Accepted mail.
2600
+ * - `archive`: The message's conversation was filed away.
2601
+ * - `spam`: The message failed sender authentication.
2602
+ * - `blocked`: The message was rejected by the mailbox's receive policy or rules.
2603
+ *
2604
+ * A received message also has `unread` until it is read. `trash` marks a message in the trash, in either direction. Custom labels share the same list, and a message has at most 20 labels in total.
2553
2605
  *
2554
2606
  */
2555
2607
  labels: Array<string>;
2556
2608
  /**
2557
- * Folded delivery status of a sent message: `accepted`, `sent` (provider handoff), `delivered` (all attempted recipients delivered), or `failed` (terminal failure). Null for received messages.
2609
+ * Folded delivery status of a sent message:
2610
+ *
2611
+ * - `accepted`: Accepted for sending.
2612
+ * - `sent`: Handed off to the provider.
2613
+ * - `delivered`: All attempted recipients delivered.
2614
+ * - `failed`: Terminal failure.
2615
+ *
2616
+ * Null for received messages.
2558
2617
  *
2559
2618
  */
2560
2619
  readonly status: string | null;
2561
2620
  /**
2562
- * Terminal per-recipient delivery outcomes of a sent message, folded in as they become known part of the message's durable memory. Null for received messages and before any recipient reaches a terminal state. Per-recipient event detail lives on the sent-message log (`source`) for 30 days.
2621
+ * Terminal per-recipient delivery outcomes of a sent message, filled in as each one becomes known and kept for the mailbox's full retention tier. Null for received messages and before any recipient reaches a terminal state. Per-recipient event detail lives on the sent-message log (`source`) for 30 days.
2563
2622
  *
2564
2623
  */
2565
2624
  readonly recipients: Array<EmailThreadMessageRecipient> | null;
2566
2625
  /**
2567
- * Whether the sender of a received message was authenticated. `pass` means the sender's identity was verified; `fail` means it was checked and did not verify; `unknown` means no verdict could be determined and the sender should not be treated as verified. Null for sent messages. Part of the message's durable memory — readable for the mailbox's full retention period, so the verdict survives after the 30-day inbound log has expired.
2626
+ * Whether the sender of a received message was authenticated. `pass` means the sender's identity was verified. `fail` means it was checked and did not verify. `unknown` means no verdict could be determined, and the sender should not be treated as verified. Null for sent messages. This field is readable for the mailbox's full retention tier, so the verdict is still available after the 30-day received-message log has expired.
2568
2627
  *
2569
2628
  */
2570
2629
  readonly authentication: "pass" | "fail" | "unknown" | null;
2571
2630
  /**
2572
- * Whether SPF passed for the sender of a received message. Null for sent messages and when no verdict is available. Durable for the mailbox's retention period.
2631
+ * Whether SPF passed for the sender of a received message. Null for sent messages and when no verdict is available. This field is kept for the mailbox's retention tier.
2573
2632
  *
2574
2633
  */
2575
2634
  readonly spf_pass: boolean | null;
2576
2635
  /**
2577
- * Whether DKIM passed for the sender of a received message. Null for sent messages and when no verdict is available. Durable for the mailbox's retention period.
2636
+ * Whether DKIM passed for the sender of a received message. Null for sent messages and when no verdict is available. This field is kept for the mailbox's retention tier.
2578
2637
  *
2579
2638
  */
2580
2639
  readonly dkim_pass: boolean | null;
2581
2640
  /**
2582
- * Whether DMARC passed for the sender of a received message. Null for sent messages and when no verdict is available. Durable for the mailbox's retention period.
2641
+ * Whether DMARC passed for the sender of a received message. Null for sent messages and when no verdict is available. This field is kept for the mailbox's retention tier.
2583
2642
  *
2584
2643
  */
2585
2644
  readonly dmarc_pass: boolean | null;
2586
2645
  /**
2587
- * When the message will be permanently deleted: the end of the mailbox's retention period, pulled nearer (at most 30 days out) while the message is in the trash. Restore a trashed message before then with `PATCH {"labels": {"remove": ["trash"]}}`.
2646
+ * When the message will be permanently deleted: the end of the mailbox's retention tier, pulled nearer (at most 30 days out) while the message is in the trash. Restore a trashed message before then with `PATCH {"labels": {"remove": ["trash"]}}`.
2588
2647
  *
2589
2648
  */
2590
2649
  readonly purge_at: string;
@@ -2593,7 +2652,7 @@ type EmailThreadMessage = {
2593
2652
  */
2594
2653
  readonly attachment_count: number;
2595
2654
  /**
2596
- * Attachment metadata (filename, content type, size). Remains readable for the mailbox's retention period even after the attachment bytes themselves have expired.
2655
+ * Attachment metadata (filename, content type, size). Stays readable for the mailbox's retention tier even after the attachment bytes themselves have expired.
2597
2656
  *
2598
2657
  */
2599
2658
  readonly attachment_manifest: Array<EmailThreadMessageAttachment>;
@@ -2636,7 +2695,7 @@ type EmailThreadHighlights = {
2636
2695
  text?: Array<string>;
2637
2696
  };
2638
2697
  /**
2639
- * A conversation in a mailbox. Threads group related messages both directions mail the mailbox received and replies it sent and carry the conversation-level read state, labels, and participant list. Message counts reflect the messages currently retained under the mailbox's retention period.
2698
+ * A conversation in a mailbox. It groups every message in both directions, the mail the mailbox received and the replies it sent, and it holds the conversation's read state, labels, and participant list. A message is retained until it is trashed or ages past the mailbox's retention tier. Only retained messages count toward the totals below.
2640
2699
  *
2641
2700
  */
2642
2701
  type EmailThread = {
@@ -2677,11 +2736,18 @@ type EmailThread = {
2677
2736
  */
2678
2737
  readonly last_message_at: string;
2679
2738
  /**
2680
- * Direction of the most recent message `inbound` for a received message, `outbound` for a sent one.
2739
+ * Direction of the most recent message: `inbound` for a received message, `outbound` for a sent one.
2681
2740
  */
2682
2741
  readonly last_direction: "inbound" | "outbound";
2683
2742
  /**
2684
- * Labels on this conversation. Exactly one system placement label is always present — `inbox`, `archive` (filed away, done for now), `spam` (the opening message failed sender authentication), or `blocked` (rejected by the mailbox's receive policy or rules) — set by the message that started the conversation. Move a conversation by updating its labels: add `spam` to file it as spam, add `archive` to clean it out of the inbox, and add `inbox` — or remove `spam`, `blocked`, or `archive` — to bring it back. An archived conversation returns to the inbox by itself when a new message arrives. Custom labels share the same list; a conversation carries at most 20.
2743
+ * Labels on this conversation. Exactly one system placement label is always present, set by the message that started the conversation:
2744
+ *
2745
+ * - `inbox`: The conversation is in the inbox.
2746
+ * - `archive`: The conversation was filed away and is done for now.
2747
+ * - `spam`: The conversation's opening message failed sender authentication.
2748
+ * - `blocked`: The conversation's opening message was rejected by the mailbox's receive policy or rules.
2749
+ *
2750
+ * Move a conversation by updating its labels. Add `spam` to file it as spam, add `archive` to clean it out of the inbox, and add `inbox`, or remove `spam`, `blocked`, or `archive`, to bring it back. An archived conversation returns to the inbox by itself when a new message arrives. Custom labels share the same list, and a conversation has at most 20 labels in total.
2685
2751
  *
2686
2752
  */
2687
2753
  labels: Array<string>;
@@ -2694,7 +2760,7 @@ type EmailThread = {
2694
2760
  */
2695
2761
  readonly updated_at: string;
2696
2762
  /**
2697
- * Matched search fragments, keyed by the field that matched. Returned only by thread search; omitted when listing threads.
2763
+ * Matched search fragments, keyed by the field that matched. Returned only by thread search. Omitted when listing threads.
2698
2764
  *
2699
2765
  */
2700
2766
  readonly highlights?: EmailThreadHighlights;
@@ -2752,7 +2818,7 @@ type ReceiveRule = {
2752
2818
  readonly created_at: string;
2753
2819
  };
2754
2820
  /**
2755
- * A mailbox's sent and received email statistics: a period-wide summary plus a bucketed time series. `period` echoes the range and grain the server computed against; `data` is one row per bucket in chronological order.
2821
+ * A mailbox's sent and received email statistics: a period-wide summary plus a bucketed time series. `period` echoes the range and grain actually used. `data` is one row per bucket in chronological order.
2756
2822
  *
2757
2823
  */
2758
2824
  type MailboxStatsResponse = {
@@ -2764,7 +2830,7 @@ type MailboxStatsResponse = {
2764
2830
  readonly data: Array<MailboxStatsPoint>;
2765
2831
  };
2766
2832
  /**
2767
- * Per-mailbox email activity for one time bucket, bucketed by event time. Sent-mail metrics carry the same delivery, engagement, and latency breakdowns as the email stats endpoints; `received` counts mail that arrived at the mailbox. Buckets with no activity are included with zero counts and null latency percentiles.
2833
+ * Per-mailbox email activity for one time bucket, bucketed by event time. Sent-mail metrics use the same delivery, engagement, and latency breakdowns as the email stats endpoints. `received` counts mail that arrived at the mailbox. Buckets with no activity are included with zero counts and null latency percentiles.
2768
2834
  *
2769
2835
  */
2770
2836
  type MailboxStatsPoint = {
@@ -2806,9 +2872,9 @@ type EmailLatencyQuantiles = {
2806
2872
  /**
2807
2873
  * Latency percentiles (p50, p95, p99) in milliseconds for the bucket. On the summary endpoint these are computed across the whole period rather than per bucket. Three families are reported:
2808
2874
  *
2809
- * - `processing`: time from accepting the send to handing the message off for delivery, covering internal queue depth and handoff. Measured per processed recipient; null when no recipient in the bucket has reached the processed stage.
2810
- * - `delivery`: time from handoff to the receiving mail server accepting the message, dominated by recipient-side delivery behaviour. Measured per delivered recipient; null when no deliveries occurred in the bucket.
2811
- * - `total`: end-to-end time from accepting the send to delivery, the most useful tile for a customer SLO. Measured per delivered recipient; null when no deliveries occurred in the bucket.
2875
+ * - `processing`: Time from accepting the send to handing the message off for delivery. Measured per processed recipient; null when no recipient in the bucket has reached the processed stage.
2876
+ * - `delivery`: Time from handoff to the receiving mail server accepting the message, dominated by recipient-side delivery behavior. Measured per delivered recipient; null when no deliveries occurred in the bucket.
2877
+ * - `total`: End-to-end time from accepting the send to delivery, and the number most worth watching against your own delivery targets. Measured per delivered recipient; null when no deliveries occurred in the bucket.
2812
2878
  *
2813
2879
  * Each family is reported independently and is omitted entirely when no qualifying event contributed a latency measurement in the bucket (including when latency for that stage has not yet been recorded for the workspace), so `processing` can be present while `delivery` and `total` are absent. A client must handle a missing family, and a null p50/p95/p99 within a present family, by rendering a placeholder rather than assuming a number.
2814
2880
  *
@@ -2819,7 +2885,7 @@ type EmailLatencyStats = {
2819
2885
  total?: EmailLatencyQuantiles;
2820
2886
  };
2821
2887
  /**
2822
- * Engagement counts and rates for the scope of the containing row (a time bucket, a breakdown dimension, or the whole period). `opens`, `opens_non_prefetched` and `clicks` count distinct engagement events (deduplicated occurrences); the `unique_*` fields count distinct recipients; `unsubscribes` counts distinct unsubscribe events. Counts are attributed by event time (not send time), so an open recorded today for a message sent earlier counts in today's row. Counts are deduplicated with a scalable approximate counting method, so very large counts are close estimates rather than exact tallies. Each rate divides the counts in this scope and is null when its denominator is zero.
2888
+ * Engagement counts and rates for the scope of the containing row (a time bucket, a breakdown dimension, or the whole period). `opens`, `opens_non_prefetched` and `clicks` count distinct engagement events (deduplicated occurrences). The `unique_*` fields count distinct recipients. `unsubscribes` counts distinct unsubscribe events. Counts are attributed by event time (not send time), so an open recorded today for a message sent earlier counts in today's row. Counts are deduplicated with a scalable approximate counting method, so very large counts are close estimates rather than exact tallies. Each rate divides the counts in this scope and is null when its denominator is zero.
2823
2889
  *
2824
2890
  */
2825
2891
  type EmailEngagementStats = {
@@ -2884,7 +2950,7 @@ type EmailBounceStatsWithRates = {
2884
2950
  */
2885
2951
  readonly soft: number;
2886
2952
  /**
2887
- * Distinct recipients bounced by an upstream policy block (relaying denied, blocklisted domain).
2953
+ * Distinct recipients refused by a policy at the receiving end, such as relaying denied or a blocklisted domain.
2888
2954
  */
2889
2955
  readonly admin: number;
2890
2956
  /**
@@ -2922,12 +2988,21 @@ type EmailBounceStatsWithRates = {
2922
2988
  readonly undetermined_rate: number | null;
2923
2989
  };
2924
2990
  /**
2925
- * Delivery pipeline counts and rates for the scope of the containing row (a time bucket, a breakdown dimension, or the whole period). Every count is the number of distinct recipients that reached the named lifecycle stage in scope (on the period summary, the sum of the per-bucket distinct counts), attributed by event time (not send time): a recipient delivered on Monday counts in Monday's row, and a recipient who bounced then succeeded on a retry can appear in both `bounced` and `delivered`. Counts are deduplicated with a scalable approximate counting method, so very large counts are close estimates rather than exact tallies. These counts are successive lifecycle stages, not interchangeable categories: `rejected` happens before any send attempt (suppression, policy, generation failure); `deferred` is a temporary in-flight delay still being retried; `bounced` (with its hard/soft/admin/block/undetermined sub-types) is a delivery failure; and `complained` is post-delivery spam feedback. Each rate is a fraction in the range 0 to 1 and is null when its denominator is zero. `accepted` is reported only where it can be attributed (time buckets and the period summary); breakdown rows omit it.
2991
+ * Delivery counts and rates for the scope of the containing row (a time bucket, a breakdown dimension, or the whole period). Every count is the number of distinct recipients that reached the named lifecycle stage in scope (on the period summary, the sum of the per-bucket distinct counts), attributed by event time (not send time): a recipient delivered on Monday counts in Monday's row, and a recipient who bounced then succeeded on a retry can appear in both `bounced` and `delivered`. Very large counts are close estimates rather than exact tallies.
2992
+ *
2993
+ * These counts are successive lifecycle stages, so a recipient can appear in more than one:
2994
+ *
2995
+ * - `rejected`: Happens before any send attempt, from suppression, policy, or a generation failure.
2996
+ * - `deferred`: A temporary in-flight delay that is still being retried.
2997
+ * - `bounced`: A delivery failure, with its own hard, soft, admin, block, and undetermined sub-types.
2998
+ * - `complained`: Post-delivery spam feedback.
2999
+ *
3000
+ * Each rate is a fraction in the range 0 to 1 and is null when its denominator is zero. `accepted` is reported only where it can be attributed (time buckets and the period summary). Breakdown rows omit it.
2926
3001
  *
2927
3002
  */
2928
3003
  type EmailDeliveryStats = {
2929
3004
  /**
2930
- * Distinct recipients accepted for delivery after suppression filtering. Reported on time buckets and the period summary; omitted on breakdown rows, whose rollups do not carry it.
3005
+ * Distinct recipients accepted for delivery after suppression filtering. Reported on time buckets and the period summary. Breakdown rows leave it out, because their rollups do not have it.
2931
3006
  */
2932
3007
  readonly accepted?: number;
2933
3008
  /**
@@ -2939,7 +3014,7 @@ type EmailDeliveryStats = {
2939
3014
  */
2940
3015
  readonly delivered: number;
2941
3016
  /**
2942
- * Distinct recipients whose delivery failed. Approximately the sum of the five `bounces.*` sub-counts (hard, soft, admin, block, undetermined); the totals are computed independently so they may differ slightly at the approximation error.
3017
+ * Distinct recipients whose delivery failed. This is approximately the sum of the five `bounces.*` sub-counts (hard, soft, admin, block, undetermined). The two totals are worked out independently, so they can differ slightly.
2943
3018
  *
2944
3019
  */
2945
3020
  readonly bounced: number;
@@ -2981,7 +3056,7 @@ type EmailDeliveryStats = {
2981
3056
  */
2982
3057
  readonly delivery_rate: number | null;
2983
3058
  /**
2984
- * Share of this scope's delivery attempts that ultimately failed (inband or out-of-band), computed as `all_bounces / (delivered + bounced)`. Because `oob_bounces` counts events rather than recipients, `all_bounces` can exceed the attempt count; the rate is clamped to 1. Null when there were no attempts.
3059
+ * Share of this scope's delivery attempts that ultimately failed (inband or out-of-band), computed as `all_bounces / (delivered + bounced)`. Because `oob_bounces` counts events rather than recipients, `all_bounces` can exceed the attempt count. The rate is clamped to 1. Null when there were no attempts.
2985
3060
  *
2986
3061
  */
2987
3062
  readonly bounce_rate: number | null;
@@ -2992,7 +3067,7 @@ type EmailDeliveryStats = {
2992
3067
  readonly complaint_rate: number | null;
2993
3068
  };
2994
3069
  /**
2995
- * Single-row aggregate of the mailbox's email activity across the full requested period. Counts are sums of per-bucket counts across the window; latency percentiles are computed across the whole period rather than summed per bucket. Rates are null when their denominator is zero.
3070
+ * Single-row aggregate of the mailbox's email activity across the full requested period. Counts are sums of per-bucket counts across the window. Latency percentiles are computed across the whole period rather than summed per bucket. Rates are null when their denominator is zero.
2996
3071
  *
2997
3072
  */
2998
3073
  type MailboxStatsSummary = {
@@ -3018,22 +3093,22 @@ type StatsGrain = "day" | "hour";
3018
3093
  */
3019
3094
  type EmailStatsSeriesPeriod = {
3020
3095
  /**
3021
- * Inclusive start of the window. A calendar day (YYYY-MM-DD, in the requested `timezone`) on the day grain; on the hour grain, an RFC 3339 UTC instant marking the start of the first hour bucket, which falls on a local hour boundary when `timezone` is set.
3096
+ * Inclusive start of the window. A calendar day (YYYY-MM-DD, in the requested `timezone`) on the day grain. On the hour grain, an RFC 3339 UTC instant marking the start of the first hour bucket, which falls on a local hour boundary when `timezone` is set.
3022
3097
  */
3023
3098
  readonly from: string;
3024
3099
  /**
3025
- * Inclusive end of the window. A calendar day (YYYY-MM-DD, in the requested `timezone`) on the day grain; on the hour grain, an RFC 3339 UTC instant marking the start of the last hour bucket, which falls on a local hour boundary when `timezone` is set.
3100
+ * Inclusive end of the window. A calendar day (YYYY-MM-DD, in the requested `timezone`) on the day grain. On the hour grain, an RFC 3339 UTC instant marking the start of the last hour bucket, which falls on a local hour boundary when `timezone` is set.
3026
3101
  */
3027
3102
  readonly to: string;
3028
3103
  readonly grain: StatsGrain;
3029
3104
  /**
3030
- * The instant the statistics in this response are current to: events recorded up to roughly this time are reflected, while more recent events may not be yet. Statistics are served from a rolling aggregation that refreshes every few seconds, so a response is near-real-time but not live; use this field to label data freshness rather than assuming the numbers are to-the-second. Null when the freshness boundary is not being reported.
3105
+ * The instant the statistics in this response are current to: events recorded up to roughly this time are reflected, while more recent events may not be yet. Statistics are served from a rolling aggregation that refreshes every few seconds, so a response reflects data from up to a few seconds ago. Use this field to label data freshness rather than assuming the numbers are to-the-second. Null when the freshness boundary is not being reported.
3031
3106
  *
3032
3107
  */
3033
3108
  readonly data_as_of?: string | null;
3034
3109
  };
3035
3110
  /**
3036
- * Fields to update on a mailbox. Omitted fields are unchanged; fields set to null are cleared. The address and domain are immutable.
3111
+ * Fields to update on a mailbox. Omitted fields are unchanged. Fields set to null are cleared. The address and domain are immutable.
3037
3112
  */
3038
3113
  type MailboxUpdate = {
3039
3114
  /**
@@ -3049,11 +3124,11 @@ type MailboxUpdate = {
3049
3124
  */
3050
3125
  receive_policy?: "open" | "replies_only" | "allowlist" | "drop";
3051
3126
  /**
3052
- * How long the mailbox remembers message metadata and extracted text. Lowering the tier deletes memory older than the new horizon and requires `confirm=true` when messages older than the new horizon would be deleted. Only `30d` is available today; additional tiers are planned.
3127
+ * How long the mailbox remembers message metadata and extracted text. Lowering the tier deletes remembered messages older than the new horizon, and requires `confirm=true` when that would happen.
3053
3128
  */
3054
3129
  retention_tier?: "30d";
3055
3130
  /**
3056
- * Replaces the mailbox's key/value data. Up to 2 KB; keys starting with `__bird` are reserved.
3131
+ * Replaces the mailbox's key/value data. Up to 2 KB. Keys starting with `__bird` are reserved.
3057
3132
  */
3058
3133
  metadata?: {
3059
3134
  [key: string]: unknown;
@@ -3064,11 +3139,11 @@ type MailboxUpdate = {
3064
3139
  */
3065
3140
  type MailboxCreate = {
3066
3141
  /**
3067
- * The local part of the mailbox address (the part before `@`). Letters, digits, dots, underscores, and hyphens; stored lowercase. On the shared `inbox.ai` domain, separators must sit between letters or digits (no leading, trailing, or repeated separators), reserved names such as `postmaster` or `abuse` are unavailable, and choosing your own local part uses one of your plan's custom-handle allowance slots (generated addresses are always available). Omit to have Bird generate a random local part.
3142
+ * The local part of the mailbox address (the part before `@`). Letters, digits, dots, underscores, and hyphens. Stored lowercase. On the shared `inbox.ai` domain, separators must sit between letters or digits (no leading, trailing, or repeated separators), reserved names such as `postmaster` or `abuse` are unavailable, and choosing your own local part uses one of your plan's custom-handle allowance slots (generated addresses are always available). Omit it and we generate a random local part.
3068
3143
  */
3069
3144
  local_part?: string;
3070
3145
  /**
3071
- * The domain the address lives under. Defaults to `inbox.ai`, Bird's shared mailbox domain, where creating the mailbox claims the address for your organization: first come, first served, and permanently reserved to your organization even after the mailbox is deleted. May instead name one of your own domains that is enabled for receiving email.
3146
+ * The domain the address lives under. Defaults to `inbox.ai`, our shared mailbox domain, where creating the mailbox claims the address for your organization: first come, first served, and permanently reserved to your organization even after the mailbox is deleted. May instead name one of your own domains that is enabled for receiving email.
3072
3147
  */
3073
3148
  domain?: string;
3074
3149
  /**
@@ -3080,15 +3155,23 @@ type MailboxCreate = {
3080
3155
  */
3081
3156
  default_reply_to?: string;
3082
3157
  /**
3083
- * Which inbound mail the mailbox accepts. `open` accepts everything not blocked by a rule; `replies_only` accepts only replies to messages this mailbox has sent (a reply must match a message the mailbox sent, not merely land in an existing thread); `allowlist` accepts only senders matching an allow rule; `drop` stores nothing.
3158
+ * Which inbound mail the mailbox accepts:
3159
+ *
3160
+ * - `open`: Accepts everything not blocked by a rule.
3161
+ * - `replies_only`: Accepts only replies to messages this mailbox has
3162
+ * sent. A reply must match a message the mailbox sent. Landing in an
3163
+ * existing thread by itself does not count.
3164
+ * - `allowlist`: Accepts only senders matching an allow rule.
3165
+ * - `drop`: Stores nothing.
3166
+ *
3084
3167
  */
3085
3168
  receive_policy?: "open" | "replies_only" | "allowlist" | "drop";
3086
3169
  /**
3087
- * How long the mailbox remembers message metadata and extracted text. Original rendered source is always available for 30 days regardless of tier. Only `30d` is available today; additional tiers are planned.
3170
+ * How long the mailbox remembers message metadata and extracted text. Original rendered source is always available for 30 days regardless of tier.
3088
3171
  */
3089
3172
  retention_tier?: "30d";
3090
3173
  /**
3091
- * Your own key/value data to attach to the mailbox. Up to 2 KB; keys starting with `__bird` are reserved.
3174
+ * Your own key/value data to attach to the mailbox. Up to 2 KB. Keys starting with `__bird` are reserved.
3092
3175
  */
3093
3176
  metadata?: {
3094
3177
  [key: string]: unknown;
@@ -3130,11 +3213,20 @@ type Mailbox = {
3130
3213
  */
3131
3214
  default_reply_to: string | null;
3132
3215
  /**
3133
- * Which inbound mail the mailbox accepts. `open` accepts everything not blocked by a rule; `replies_only` accepts only replies to messages this mailbox has sent (a reply must match a message the mailbox sent, not merely land in an existing thread); `allowlist` accepts only senders matching an allow rule (replies to prior outbound are always admitted unless blocked); `drop` stores nothing.
3216
+ * Which inbound mail the mailbox accepts:
3217
+ *
3218
+ * - `open`: Accepts everything not blocked by a rule.
3219
+ * - `replies_only`: Accepts only replies to messages this mailbox has
3220
+ * sent. A reply must match a message the mailbox sent. Landing in an
3221
+ * existing thread by itself does not count.
3222
+ * - `allowlist`: Accepts only senders matching an allow rule. Replies to
3223
+ * prior outbound mail are always admitted unless blocked.
3224
+ * - `drop`: Stores nothing.
3225
+ *
3134
3226
  */
3135
3227
  receive_policy: "open" | "replies_only" | "allowlist" | "drop";
3136
3228
  /**
3137
- * Lifecycle state. Suspended mailboxes stop emitting events; inbound mail is retained as blocked.
3229
+ * Lifecycle state. Suspended mailboxes stop emitting events. Inbound mail is retained as blocked.
3138
3230
  */
3139
3231
  readonly state: "active" | "suspended";
3140
3232
  /**
@@ -3147,7 +3239,7 @@ type Mailbox = {
3147
3239
  */
3148
3240
  readonly inbound_address_id: InboundAddressId;
3149
3241
  /**
3150
- * How long the mailbox remembers message metadata and extracted text. Original rendered source (HTML, raw message, attachments) is always available for 30 days regardless of tier. `3y` and `10y` are reserved future tiers.
3242
+ * How long the mailbox remembers message metadata and extracted text. Original rendered source (HTML, raw message, attachments) is always available for 30 days regardless of tier.
3151
3243
  */
3152
3244
  retention_tier: "30d" | "90d" | "1y";
3153
3245
  /**
@@ -3164,13 +3256,13 @@ type Mailbox = {
3164
3256
  */
3165
3257
  readonly unread_thread_count?: number | null;
3166
3258
  /**
3167
- * Your own key/value data attached to the mailbox. Up to 2 KB; keys starting with `__bird` are reserved.
3259
+ * Your own key/value data attached to the mailbox. Up to 2 KB. Keys starting with `__bird` are reserved.
3168
3260
  */
3169
3261
  metadata: {
3170
3262
  [key: string]: unknown;
3171
3263
  };
3172
3264
  /**
3173
- * Whether Bird generated the local part of the address. `false` means a custom handle was chosen at creation; on the shared `inbox.ai` domain a custom handle counts against your plan's custom-handle allowance.
3265
+ * Whether we generated the local part of the address. `false` means a custom handle was chosen at creation. On the shared `inbox.ai` domain a custom handle counts against your plan's custom-handle allowance.
3174
3266
  */
3175
3267
  readonly local_part_generated?: boolean;
3176
3268
  /**
@@ -3512,17 +3604,17 @@ type EmailStatsByBroadcastResponse = {
3512
3604
  */
3513
3605
  readonly data: Array<EmailBroadcastStatsPoint>;
3514
3606
  /**
3515
- * Total number of distinct broadcasts with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
3607
+ * Total number of distinct broadcasts with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
3516
3608
  *
3517
3609
  */
3518
3610
  readonly total: number;
3519
3611
  };
3520
3612
  /**
3521
- * Aggregate delivery, engagement, and latency stats for the messages of a single broadcast over the requested period.
3613
+ * Delivery, engagement and latency figures for one broadcast's messages over the period you asked for.
3522
3614
  */
3523
3615
  type EmailBroadcastStatsPoint = {
3524
3616
  /**
3525
- * The broadcast this row aggregates, the same identifier returned by the broadcast endpoints. Only messages sent as part of a broadcast carry a broadcast identifier; one-off and transactional sends are not included in this breakdown.
3617
+ * The broadcast this row covers, the same ID the broadcast endpoints return. Only mail sent as part of a broadcast has a broadcast ID, so one-off and transactional sends do not appear in this breakdown at all.
3526
3618
  */
3527
3619
  readonly broadcast_id: string;
3528
3620
  readonly delivery: EmailDeliveryStats;
@@ -3530,7 +3622,7 @@ type EmailBroadcastStatsPoint = {
3530
3622
  readonly latency: EmailLatencyStats;
3531
3623
  };
3532
3624
  /**
3533
- * The date range the server actually computed against. Echoed back so clients can render the period without tracking it themselves and so cached responses can be keyed by what was queried.
3625
+ * The date range this response was actually computed against. Echoed back so clients can render the period without tracking it themselves and so cached responses can be keyed by what was queried.
3534
3626
  *
3535
3627
  */
3536
3628
  type EmailStatsPeriod = {
@@ -3543,7 +3635,7 @@ type EmailStatsPeriod = {
3543
3635
  */
3544
3636
  readonly to: string;
3545
3637
  /**
3546
- * The instant the statistics in this response are current to: events recorded up to roughly this time are reflected, while more recent events may not be yet. Statistics are served from a rolling aggregation that refreshes every few seconds, so a response is near-real-time but not live; use this field to label data freshness (for example "as of 14:03") rather than assuming the numbers are to-the-second. Null when the freshness boundary is not being reported.
3638
+ * The instant the statistics in this response are current to: events recorded up to roughly this time are reflected, while more recent events may not be yet. Statistics are served from a rolling aggregation that refreshes every few seconds, so a response reflects data from up to a few seconds ago. Use this field to label data freshness (for example "as of 14:03") rather than assuming the numbers are to-the-second. Null when the freshness boundary is not being reported.
3547
3639
  *
3548
3640
  */
3549
3641
  readonly data_as_of?: string | null;
@@ -3561,13 +3653,13 @@ type EmailStatsByComplaintTypeResponse = {
3561
3653
  */
3562
3654
  readonly data: Array<EmailComplaintTypeStatsPoint>;
3563
3655
  /**
3564
- * Total number of distinct feedback types with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
3656
+ * Total number of distinct feedback types with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
3565
3657
  *
3566
3658
  */
3567
3659
  readonly total: number;
3568
3660
  };
3569
3661
  /**
3570
- * Complaint counts for a single feedback-loop complaint type over the requested period. A complaint type is recorded only on spam-complaint events, so this breakdown reports the complained count for each type and nothing else (a complaint event carries no delivery or engagement context to aggregate).
3662
+ * Complaint counts for a single feedback-loop complaint type over the requested period. A complaint type is recorded only on spam-complaint events, so this breakdown reports the complained count for each type and nothing else. A complaint event has no delivery or engagement information attached to it, so there is nothing else here to count.
3571
3663
  *
3572
3664
  */
3573
3665
  type EmailComplaintTypeStatsPoint = {
@@ -3593,7 +3685,7 @@ type EmailStatsByBounceCodeResponse = {
3593
3685
  */
3594
3686
  readonly data: Array<EmailBounceCodeStatsPoint>;
3595
3687
  /**
3596
- * Total number of distinct SMTP error codes with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
3688
+ * Total number of distinct SMTP error codes with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
3597
3689
  *
3598
3690
  */
3599
3691
  readonly total: number;
@@ -3614,7 +3706,7 @@ type EmailBounceStats = {
3614
3706
  */
3615
3707
  readonly soft: number;
3616
3708
  /**
3617
- * Distinct recipients bounced by an upstream policy block (relaying denied, blocklisted domain). Triage usually focuses on content or sender configuration rather than recipient cleanup.
3709
+ * Distinct recipients refused by a policy at the receiving end, such as relaying denied or a blocklisted domain. Fixing these usually means changing your content or your sender configuration, not cleaning up the recipient list.
3618
3710
  *
3619
3711
  */
3620
3712
  readonly admin: number;
@@ -3630,7 +3722,7 @@ type EmailBounceStats = {
3630
3722
  readonly undetermined: number;
3631
3723
  };
3632
3724
  /**
3633
- * Bounce counts for a single SMTP status code over the requested period, with the per-type breakdown. This is a deliverability-debugging view keyed on what the receiving server returned, so it reports the failure side only (bounced recipients and their hard/soft/admin/block/undetermined split) and carries no delivered, open, or rate fields.
3725
+ * Bounce counts for a single SMTP status code over the requested period, with the per-type breakdown. This is a deliverability-debugging view keyed on what the receiving mail server returned, so it only reports the failure side: bounced recipients, and their `hard`, `soft`, `admin`, `block`, and `undetermined` split. It has no delivered, open, or rate fields.
3634
3726
  *
3635
3727
  */
3636
3728
  type EmailBounceCodeStatsPoint = {
@@ -3639,7 +3731,7 @@ type EmailBounceCodeStatsPoint = {
3639
3731
  */
3640
3732
  readonly smtp_error_code: string;
3641
3733
  /**
3642
- * Distinct recipients whose delivery failed with this SMTP status code. Approximately the sum of the five `bounces.*` sub-counts; the totals are computed independently so they may differ slightly at the approximation error.
3734
+ * Distinct recipients whose delivery failed with this SMTP status code, approximately equal to the sum of the five `bounces.*` sub-counts. The two are computed independently, so they can differ slightly because of approximation.
3643
3735
  */
3644
3736
  readonly bounced: number;
3645
3737
  readonly bounces: EmailBounceStats;
@@ -3657,13 +3749,13 @@ type EmailStatsByClientResponse = {
3657
3749
  */
3658
3750
  readonly data: Array<EmailClientStatsPoint>;
3659
3751
  /**
3660
- * Total number of distinct values of the requested `group_by` facet with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
3752
+ * Total number of distinct values of the requested `group_by` facet with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
3661
3753
  *
3662
3754
  */
3663
3755
  readonly total: number;
3664
3756
  };
3665
3757
  /**
3666
- * Open and click counts for a breakdown row whose dimension is resolved from engagement events only. `opens`, `opens_non_prefetched` and `clicks` count distinct engagement events (deduplicated occurrences); the `unique_*` fields count distinct recipients. Rates and unsubscribe counts are not included: there is no per-dimension delivered denominator for a rate, and unsubscribe events do not carry the engagement context this breakdown is keyed on.
3758
+ * Open and click counts for a breakdown row whose dimension is resolved from engagement events only. `opens`, `opens_non_prefetched`, and `clicks` count events, not people: the same recipient opening or clicking more than once counts each time. The `unique_*` fields count distinct recipients instead, so a recipient who opened five times only counts once there. Rates and unsubscribe counts are not included here. There is no per-dimension delivered count to use as a rate's denominator, and an unsubscribe event has none of the information this breakdown is grouped by, so it cannot be placed on a row.
3667
3759
  *
3668
3760
  */
3669
3761
  type EmailEngagementCounts = {
@@ -3695,20 +3787,20 @@ type EmailEngagementCounts = {
3695
3787
  readonly unique_clicks: number;
3696
3788
  };
3697
3789
  /**
3698
- * Engagement counts for messages opened or clicked from a single email client, operating system, or device type over the requested period. The reading environment is resolved from open and click events only, so this breakdown reports engagement activity (opens, clicks, and the recipients behind them); it carries no delivery counts and no open/click rates, because the receiving mail server reports delivery without a client or device, leaving no per-client delivered denominator to divide by. Exactly one of `email_client`, `os`, and `device_type` is populated, selected by the request's `group_by`; the other two are null. Engagement environment is detected from the opening client and is subject to the same inbox-privacy prefetch effects as the open counts (the `opens_non_prefetched` figure excludes auto-fetched opens).
3790
+ * Engagement counts for messages opened or clicked from a single email client, operating system, or device type over the requested period. The reading environment is resolved from open and click events only, so this breakdown reports engagement activity: opens, clicks, and the recipients behind them. It has no delivery counts and no open or click rates, because the receiving mail server reports delivery without a client or device, so there is no per-client delivered denominator to divide by. Exactly one of `email_client`, `os`, and `device_type` is populated, selected by the request's `group_by`. The other two are null. The detected client is also affected by inbox-privacy prefetching, the same way open counts are: `opens_non_prefetched` excludes opens that were auto-fetched by an inbox privacy feature rather than by a person actually opening the message.
3699
3791
  *
3700
3792
  */
3701
3793
  type EmailClientStatsPoint = {
3702
3794
  /**
3703
- * The mail client this row aggregates (for example `Gmail`, `Apple Mail`, `Outlook`). Populated only when `group_by=email_client`; null otherwise.
3795
+ * The mail client this row aggregates (for example `Gmail`, `Apple Mail`, `Outlook`). Populated only when `group_by=email_client`. Null otherwise.
3704
3796
  */
3705
3797
  readonly email_client: string | null;
3706
3798
  /**
3707
- * The operating system this row aggregates (for example `iOS`, `Android`, `Windows`, `macOS`). Populated only when `group_by=os`; null otherwise.
3799
+ * The operating system this row aggregates (for example `iOS`, `Android`, `Windows`, `macOS`). Populated only when `group_by=os`. Null otherwise.
3708
3800
  */
3709
3801
  readonly os: string | null;
3710
3802
  /**
3711
- * The device type this row aggregates (for example `mobile`, `desktop`, `tablet`). Populated only when `group_by=device_type`; null otherwise.
3803
+ * The device type this row aggregates (for example `mobile`, `desktop`, `tablet`). Populated only when `group_by=device_type`. Null otherwise.
3712
3804
  */
3713
3805
  readonly device_type: string | null;
3714
3806
  readonly engagement: EmailEngagementCounts;
@@ -3726,13 +3818,13 @@ type EmailStatsByLocationResponse = {
3726
3818
  */
3727
3819
  readonly data: Array<EmailLocationStatsPoint>;
3728
3820
  /**
3729
- * Total number of distinct locations at the requested `group_by` level with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
3821
+ * Total number of distinct locations at the requested `group_by` level with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
3730
3822
  *
3731
3823
  */
3732
3824
  readonly total: number;
3733
3825
  };
3734
3826
  /**
3735
- * Open and click counts for messages engaged with from a single location over the requested period. Location is resolved from open and click events only, so this breakdown reports engagement activity (opens, clicks, and the recipients behind them); it carries no delivery counts and no open/click rates, because the receiving mail server reports delivery without a recipient location, leaving no per-location delivered denominator to divide by. Each row always includes all three of `country`, `region`, and `city`; the levels below the requested `group_by` are null.
3827
+ * Open and click counts for messages engaged with from a single location over the requested period. Location is resolved from open and click events only, so this breakdown reports engagement activity: opens, clicks, and the recipients behind them. It has no delivery counts and no open or click rates, because the receiving mail server reports delivery without a recipient location, so there is no per-location delivered denominator to divide by. Each row always includes all three of `country`, `region`, and `city`; the levels below the requested `group_by` are null.
3736
3828
  *
3737
3829
  */
3738
3830
  type EmailLocationStatsPoint = {
@@ -3756,25 +3848,28 @@ type EmailLocationStatsPoint = {
3756
3848
  */
3757
3849
  type EmailEngagementSortMetric = "opens" | "opens_non_prefetched" | "unique_opens" | "unique_opens_non_prefetched" | "clicks" | "unique_clicks";
3758
3850
  /**
3759
- * Per-template breakdown for the requested period, ranked by the `sort` metric (default `processed`) descending and capped at the requested `limit` (default 50, max 200).
3851
+ * A breakdown of stats per template for the requested period. Rows are ranked by the `sort` metric (`processed` by default) descending, and capped at the requested `limit` (50 by default, 200 at most).
3852
+ *
3760
3853
  */
3761
3854
  type EmailStatsByTemplateResponse = {
3762
3855
  /**
3763
- * The date range the response covers (echoed back from the request), plus `data_as_of`, the freshness boundary the data is current to.
3856
+ * The date range this response covers, echoed back from what you requested, plus `data_as_of`: how far the underlying data is currently up to date.
3857
+ *
3764
3858
  */
3765
3859
  period: EmailStatsPeriod;
3766
3860
  /**
3767
- * Template breakdown rows, ranked by the `sort` metric (default `processed`) descending. Empty when no templated messages were active in the period.
3861
+ * One row per template, ranked by the `sort` metric (`processed` by default) descending. Empty when no messages were sent with a template during the period.
3862
+ *
3768
3863
  */
3769
3864
  readonly data: Array<EmailTemplateStatsPoint>;
3770
3865
  /**
3771
- * Total number of distinct templates with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
3866
+ * How many distinct templates had activity in the period, regardless of `limit`. When this is higher than the number of rows in `data`, the ranking got cut off. Raise `limit` (up to 200), or narrow the date range, to see the rest.
3772
3867
  *
3773
3868
  */
3774
3869
  readonly total: number;
3775
3870
  };
3776
3871
  /**
3777
- * One point in a breakdown row's trend series: the headline delivery and engagement rates for that row's dimension value over a single day or hour. Returned only when `include_trend=true`; the bucket grain (day or hour) follows the `trend_grain` parameter. Counts and rates are approximate at scale.
3872
+ * One point in a breakdown row's trend series: the headline delivery and engagement rates for that row's dimension value over a single day or hour. Returned only when `include_trend=true`. The bucket grain (day or hour) follows the `trend_grain` parameter. Counts and rates are approximate at scale.
3778
3873
  *
3779
3874
  */
3780
3875
  type EmailStatsSeriesPoint = {
@@ -3799,32 +3894,34 @@ type EmailStatsSeriesPoint = {
3799
3894
  */
3800
3895
  readonly bounce_rate: number | null;
3801
3896
  /**
3802
- * Complaint rate for this bucket, as a fraction; event-time attribution can push it above 1 when complaints outrun the bucket's deliveries. Null when nothing was delivered in the bucket. On a sending-IP row complaints are not attributed to the IP, so this reads 0 in buckets that had deliveries and null in buckets that had none.
3897
+ * Complaint rate for this bucket, as a fraction. Event-time attribution can push it above 1 when complaints outrun the bucket's deliveries. Null when nothing was delivered in the bucket. On a sending-IP row complaints are not attributed to the IP, so this reads 0 in buckets that had deliveries and null in buckets that had none.
3803
3898
  */
3804
3899
  readonly complaint_rate: number | null;
3805
3900
  /**
3806
- * Open rate for this bucket, as a fraction; event-time attribution can push it above 1 when opens outrun the bucket's deliveries. Null when nothing was delivered in the bucket. On a sending-IP row engagement is not attributed to the IP, so this reads 0 in buckets that had deliveries and null in buckets that had none.
3901
+ * Open rate for this bucket, as a fraction. Event-time attribution can push it above 1 when opens outrun the bucket's deliveries. Null when nothing was delivered in the bucket. On a sending-IP row engagement is not attributed to the IP, so this reads 0 in buckets that had deliveries and null in buckets that had none.
3807
3902
  */
3808
3903
  readonly open_rate: number | null;
3809
3904
  /**
3810
- * Click rate for this bucket, as a fraction; event-time attribution can push it above 1 when clicks outrun the bucket's deliveries. Null when nothing was delivered in the bucket. On a sending-IP row engagement is not attributed to the IP, so this reads 0 in buckets that had deliveries and null in buckets that had none.
3905
+ * Click rate for this bucket, as a fraction. Event-time attribution can push it above 1 when clicks outrun the bucket's deliveries. Null when nothing was delivered in the bucket. On a sending-IP row engagement is not attributed to the IP, so this reads 0 in buckets that had deliveries and null in buckets that had none.
3811
3906
  */
3812
3907
  readonly click_rate: number | null;
3813
3908
  };
3814
3909
  type EmailTemplateId = string;
3815
3910
  /**
3816
- * Aggregate delivery, engagement, and latency stats for the messages sent with a single template over the requested period.
3911
+ * Delivery, engagement, and latency numbers for every message sent with one template over the requested period.
3817
3912
  */
3818
3913
  type EmailTemplateStatsPoint = {
3819
3914
  /**
3820
- * The template this row aggregates, the same identifier returned by the email-template endpoints. Only messages sent with a template appear in this breakdown; a template deleted after sending still appears by its ID.
3915
+ * The template this row is about, using the same `id` the email template endpoints return. Only messages sent with a template appear in this breakdown at all. If the template was deleted after it was used to send, this row still appears, keyed by that same `id`.
3916
+ *
3821
3917
  */
3822
3918
  readonly template_id: EmailTemplateId;
3823
3919
  readonly delivery: EmailDeliveryStats;
3824
3920
  readonly engagement: EmailEngagementStats;
3825
3921
  readonly latency: EmailLatencyStats;
3826
3922
  /**
3827
- * Per-bucket rate series for this template over the window. Present only when `include_trend=true`.
3923
+ * A short series of this template's delivery and engagement rates, one point per time bucket over the window. Only present when you set `include_trend=true` on the request.
3924
+ *
3828
3925
  */
3829
3926
  readonly trend?: Array<EmailStatsSeriesPoint>;
3830
3927
  };
@@ -3841,7 +3938,7 @@ type EmailStatsByRecipientDomainResponse = {
3841
3938
  */
3842
3939
  readonly data: Array<EmailRecipientDomainStatsPoint>;
3843
3940
  /**
3844
- * Total number of distinct recipient domains with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
3941
+ * Total number of distinct recipient domains with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
3845
3942
  *
3846
3943
  */
3847
3944
  readonly total: number;
@@ -3875,7 +3972,7 @@ type EmailStatsByMailboxProviderRegionResponse = {
3875
3972
  */
3876
3973
  readonly data: Array<EmailMailboxProviderRegionStatsPoint>;
3877
3974
  /**
3878
- * Total number of distinct mailbox provider and region pairs with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
3975
+ * Total number of distinct mailbox provider and region pairs with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
3879
3976
  *
3880
3977
  */
3881
3978
  readonly total: number;
@@ -3883,10 +3980,10 @@ type EmailStatsByMailboxProviderRegionResponse = {
3883
3980
  /**
3884
3981
  * Latency percentiles (p50, p95, p99) in milliseconds for the messages in this breakdown row, for breakdowns whose dimension is known only from delivery onward (sending IP, mailbox provider).
3885
3982
  *
3886
- * - `delivery`: time from handing the message off to the receiving mail server accepting it. Null when no deliveries occurred for this row in the period.
3887
- * - `total`: end-to-end time from accepting the send to delivery. Null when no deliveries occurred for this row in the period.
3983
+ * - `delivery`: Time from handing the message off to the receiving mail server accepting it. Null when no deliveries occurred for this row in the period.
3984
+ * - `total`: End-to-end time from accepting the send to delivery. Null when no deliveries occurred for this row in the period.
3888
3985
  *
3889
- * These breakdowns have no `processing` latency family. Bird only learns a row's dimension (the sending IP or recipient mailbox provider) after the upstream mail-transfer system reports delivery, bounce, deferral, or late bounce; the accept-to-processed phase happens before that binding decision, so it cannot be attributed to the dimension. Use `GET /v1/email/stats/daily` for workspace-wide processing-latency percentiles.
3986
+ * These breakdowns have no `processing` latency family. Which row a message belongs to, meaning which sending IP carried it or which mailbox provider received it, is only known once the receiving mail server has reported back with a delivery, a bounce, a deferral or a late bounce. The accept-to-processed phase is over before then, so there is no way to attribute it to a row. Use `GET /v1/email/stats/daily` for processing-latency percentiles across the whole workspace.
3890
3987
  *
3891
3988
  */
3892
3989
  type EmailDeliveryLatencyStats = {
@@ -3894,7 +3991,7 @@ type EmailDeliveryLatencyStats = {
3894
3991
  total: EmailLatencyQuantiles;
3895
3992
  };
3896
3993
  /**
3897
- * Delivery counts and rates for messages attributed to a single recipient mailbox provider. Per-provider results do not include `accepted` or `processed` counts because Bird only learns the recipient's mailbox provider after the upstream mail transfer system reports delivery/bounce/deferral/late bounce. Earlier lifecycle states (accepted, processed) cannot be attributed to a specific provider.
3994
+ * Delivery counts and rates for messages attributed to a single recipient mailbox provider. Per-provider results do not include `accepted` or `processed` counts, because we only learn the recipient's mailbox provider once the receiving mail server reports delivery, a bounce, a deferral, or a late bounce. Earlier lifecycle states (accepted, processed) cannot be attributed to a specific provider.
3898
3995
  *
3899
3996
  */
3900
3997
  type EmailMailboxProviderDeliveryStats = {
@@ -3965,18 +4062,18 @@ type EmailStatsByMailboxProviderResponse = {
3965
4062
  */
3966
4063
  readonly data: Array<EmailMailboxProviderStatsPoint>;
3967
4064
  /**
3968
- * Total number of distinct mailbox providers with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
4065
+ * Total number of distinct mailbox providers with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
3969
4066
  *
3970
4067
  */
3971
4068
  readonly total: number;
3972
4069
  };
3973
4070
  /**
3974
- * Delivery, engagement, and deliverability stats for messages grouped by a single recipient mailbox provider (`gmail`, `microsoft`, `yahoo`, `apple`, ...) over the requested period. A recipient's mailbox provider is reported by the receiving mail system, so per-provider rows cover the delivery stage onward: they omit the `accepted` and `processed` counts and the `processing` latency family, which never appear (they are not returned as null). Engagement (opens, clicks, and their rates) is included because those events are post-delivery and carry the mailbox provider.
4071
+ * Delivery, engagement, and deliverability stats for messages grouped by a single recipient mailbox provider (`gmail`, `microsoft`, `yahoo`, `apple`, ...) over the requested period. We learn a recipient's mailbox provider from the receiving mail server, so per-provider rows cover the delivery stage onward: they omit the `accepted` and `processed` counts and the `processing` latency family, which never appear at all rather than appearing as null. Engagement (opens and clicks, and their rates) is included because those events happen after delivery, once the mailbox provider is already known.
3975
4072
  *
3976
4073
  */
3977
4074
  type EmailMailboxProviderStatsPoint = {
3978
4075
  /**
3979
- * The recipient mailbox provider this row aggregates, as a lowercased classifier bucket (e.g. `gmail`, `yahoo`, `microsoft`, `apple`). The set is open and grows as new providers are categorised.
4076
+ * The recipient mailbox provider this row aggregates, as a lowercased classifier bucket (e.g. `gmail`, `yahoo`, `microsoft`, `apple`). The set is open and grows as new providers are categorized.
3980
4077
  */
3981
4078
  readonly mailbox_provider: string;
3982
4079
  readonly delivery: EmailMailboxProviderDeliveryStats;
@@ -3988,7 +4085,7 @@ type EmailMailboxProviderStatsPoint = {
3988
4085
  readonly trend?: Array<EmailStatsSeriesPoint>;
3989
4086
  };
3990
4087
  /**
3991
- * Metric to rank rows by, applied descending. Shared by the breakdowns whose attribution begins at delivery (mailbox providers, mailbox provider regions): `processed`, `rejected`, and `oob_bounces` are not part of those rows, so they are not sortable. Any count or rate the rows carry may be used; rows whose rate is undefined (zero denominator) sort last. Bounce sub-types are addressed by their nested location in each row, for example `bounces.hard` and `bounces.hard_rate`.
4088
+ * Metric to rank rows by, applied descending. Shared by the breakdowns whose attribution begins at delivery (mailbox providers, mailbox provider regions): `processed`, `rejected`, and `oob_bounces` are not part of those rows, so they are not sortable. Any count or rate on the row can be used; rows whose rate is undefined (zero denominator) sort last. Bounce sub-types use their nested location in each row, for example `bounces.hard` and `bounces.hard_rate`.
3992
4089
  *
3993
4090
  */
3994
4091
  type EmailMailboxProviderSortMetric = "delivered" | "bounced" | "complained" | "deferred" | "bounces.hard" | "bounces.soft" | "bounces.admin" | "bounces.block" | "bounces.undetermined" | "opens" | "opens_non_prefetched" | "unique_opens" | "unique_opens_non_prefetched" | "clicks" | "unique_clicks" | "unsubscribes" | "delivery_rate" | "bounce_rate" | "complaint_rate" | "open_rate" | "click_rate" | "unsubscribe_rate" | "bounces.hard_rate" | "bounces.soft_rate" | "bounces.admin_rate" | "bounces.block_rate" | "bounces.undetermined_rate";
@@ -4005,7 +4102,7 @@ type EmailStatsByCategoryResponse = {
4005
4102
  */
4006
4103
  readonly data: Array<EmailCategoryStatsPoint>;
4007
4104
  /**
4008
- * Total number of distinct categories with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
4105
+ * Total number of distinct categories with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
4009
4106
  *
4010
4107
  */
4011
4108
  readonly total: number;
@@ -4015,7 +4112,7 @@ type EmailStatsByCategoryResponse = {
4015
4112
  */
4016
4113
  type EmailCategoryStatsPoint = {
4017
4114
  /**
4018
- * The category this row aggregates, as set at send time. `transactional` is one-to-one mail triggered by a user action; `marketing` is bulk sending. New categories may be added over time.
4115
+ * The category this row aggregates, as set at send time. `transactional` is one-to-one mail triggered by a user action. `marketing` is bulk sending. New categories may be added over time.
4019
4116
  */
4020
4117
  readonly category: string;
4021
4118
  readonly delivery: EmailDeliveryStats;
@@ -4039,7 +4136,7 @@ type EmailStatsBySendingDomainResponse = {
4039
4136
  */
4040
4137
  readonly data: Array<EmailSendingDomainStatsPoint>;
4041
4138
  /**
4042
- * Total number of distinct sending domains with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
4139
+ * Total number of distinct sending domains with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
4043
4140
  *
4044
4141
  */
4045
4142
  readonly total: number;
@@ -4073,13 +4170,13 @@ type EmailStatsBySendingIpResponse = {
4073
4170
  */
4074
4171
  readonly data: Array<EmailSendingIpStatsPoint>;
4075
4172
  /**
4076
- * Total number of distinct sending IP addresses with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
4173
+ * Total number of distinct sending IP addresses with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
4077
4174
  *
4078
4175
  */
4079
4176
  readonly total: number;
4080
4177
  };
4081
4178
  /**
4082
- * Delivery counts and rates for messages attributed to a single sending IP. Per-IP results do not include `accepted` or `processed` counts because Bird only learns which sending IP a message used after the upstream mail transfer system reports delivery/bounce/deferral/late bounce. Earlier lifecycle states (accepted, processed) cannot be attributed to a specific IP. Spam complaints and out-of-band bounce notifications are also not attributed per IP on this breakdown, so `complained` and `oob_bounces` read 0 (their rates read 0 where the denominator is non-zero, null where it is zero), `effective_delivered` equals `delivered`, and `all_bounces` equals `bounced`.
4179
+ * Delivery counts and rates for messages attributed to a single sending IP. Per-IP results do not include `accepted` or `processed` counts: we only learn which sending IP a message used once it has been delivered, bounced, deferred, or bounced late, so those earlier lifecycle states cannot be attributed to a specific IP. Spam complaints and out-of-band bounce notifications are also not attributed per IP on this breakdown, so `complained` and `oob_bounces` read 0 (their rates read 0 where the denominator is non-zero, null where it is zero), `effective_delivered` equals `delivered`, and `all_bounces` equals `bounced`.
4083
4180
  *
4084
4181
  */
4085
4182
  type EmailSendingIpDeliveryStats = {
@@ -4088,11 +4185,11 @@ type EmailSendingIpDeliveryStats = {
4088
4185
  */
4089
4186
  readonly delivered: number;
4090
4187
  /**
4091
- * Distinct recipients whose delivery failed. Approximately the sum of the five `bounces.*` sub-counts (hard, soft, admin, block, undetermined); the totals are computed independently so they may differ slightly at the approximation error.
4188
+ * Distinct recipients whose delivery failed. This is approximately the sum of the five `bounces.*` sub-counts (hard, soft, admin, block, undetermined). The two are computed independently, so they can differ slightly.
4092
4189
  */
4093
4190
  readonly bounced: number;
4094
4191
  /**
4095
- * Distinct recipients who reported the message as spam. Complaints are not attributed to a sending IP, so this reads 0 on this breakdown; read complaint counts from the summary or time-series statistics instead.
4192
+ * Distinct recipients who reported the message as spam. Complaints are not attributed to a sending IP, so this reads 0 on this breakdown. Read complaint counts from the summary or time-series statistics instead.
4096
4193
  */
4097
4194
  readonly complained: number;
4098
4195
  /**
@@ -4100,7 +4197,7 @@ type EmailSendingIpDeliveryStats = {
4100
4197
  */
4101
4198
  readonly deferred: number;
4102
4199
  /**
4103
- * Out-of-band bounce events: failure notifications received after the receiving server had initially confirmed delivery. Not attributed to a sending IP on this breakdown, so this reads 0; workspace-wide out-of-band counts are on the summary and time-series statistics.
4200
+ * Out-of-band bounce events: failure notifications received after the receiving server had initially confirmed delivery. Not attributed to a sending IP on this breakdown, so this reads 0. Workspace-wide out-of-band counts are on the summary and time-series statistics.
4104
4201
  *
4105
4202
  */
4106
4203
  readonly oob_bounces: number;
@@ -4135,7 +4232,7 @@ type EmailSendingIpDeliveryStats = {
4135
4232
  };
4136
4233
  type IpPoolId = string;
4137
4234
  /**
4138
- * Delivery and latency stats for messages sent from a single IP address over the requested period. Per-IP attribution begins only after a message is processed: the upstream mail-transfer system reports the IP it used on delivery, bounce, deferral, and late-bounce events, but not at acceptance or processing time. As a result, per-IP rows omit the `accepted` and `processed` counts and the `processing` latency family, which never appear (they are not returned as null).
4235
+ * Delivery and latency stats for messages sent from a single IP address over the requested period. Per-IP attribution begins only after a message is processed: we learn which IP a message used only from its delivery, bounce, deferral, and late-bounce events, not from its acceptance or processing. As a result, per-IP rows omit the `accepted` and `processed` counts and the `processing` latency family. Those fields never appear on a per-IP row. They are not returned as null.
4139
4236
  *
4140
4237
  */
4141
4238
  type EmailSendingIpStatsPoint = {
@@ -4156,9 +4253,21 @@ type EmailSendingIpStatsPoint = {
4156
4253
  readonly trend?: Array<EmailStatsSeriesPoint>;
4157
4254
  };
4158
4255
  /**
4159
- * Single-row aggregate across the full requested period, including delivery and engagement counts plus derived rates. Use this endpoint for KPI tiles, campaign reporting, and any metric that needs a meaningful denominator; the daily and hourly endpoints carry the same rates per bucket, dividing each bucket's own counts.
4256
+ * A single row that aggregates delivery and engagement counts, plus derived
4257
+ * rates, across the whole requested period. Use this endpoint for KPI
4258
+ * tiles, campaign reporting, and anywhere you need a rate with a meaningful
4259
+ * denominator. The daily and hourly endpoints report the same rates, but
4260
+ * per bucket, each one dividing that bucket's own counts.
4160
4261
  *
4161
- * Every count is a sum of per-bucket counts across the window (per day for day windows, per hour for hour windows), so a recipient (or message) active in two buckets contributes one to each bucket and two to the period total. This matches common provider reporting and is not double-counting; it does not yield a period-distinct count. Latency percentiles, by contrast, are computed across the whole period rather than summed per bucket. Rates are null when their denominator is zero.
4262
+ * Every count is a sum of per-bucket counts across the window (per day for
4263
+ * day windows, per hour for hour windows). A recipient, or a message, that
4264
+ * is active in two buckets contributes to each of them, so it is counted
4265
+ * twice in the period total. This matches how most mailbox providers report
4266
+ * their own numbers. The effect to plan for is that the total is a sum of
4267
+ * per-bucket activity rather than a count of distinct recipients or messages
4268
+ * across the whole period. Latency percentiles work differently: they are computed
4269
+ * once across the whole period rather than summed from the buckets. A rate
4270
+ * is null when its denominator is zero.
4162
4271
  *
4163
4272
  */
4164
4273
  type EmailStatsSummary = {
@@ -4176,7 +4285,7 @@ type EmailStatsSummary = {
4176
4285
  readonly comparison?: EmailStatsComparison;
4177
4286
  };
4178
4287
  /**
4179
- * The change in each headline metric from the preceding period to the requested one. A `*_pct_change` is a signed relative change in a count, computed as `(current - previous) / previous` (so `0.5` means 50% higher, `-0.2` means 20% lower), and is null when the previous period's count was zero. A `*_rate_pp` is the signed arithmetic difference between the two periods' rate values, where each rate is a fraction in `[0,1]` (so `0.012` means the rate rose by 0.012, i.e. 1.2 percentage points; `-0.003` means it fell by 0.3 points), and is null when either period's rate is undefined (its denominator was zero). A `*_rate_pp` value ranges from `-1` to `1`: the most a rate can move between periods is from 0 to 1, or 1 to 0.
4288
+ * The change in each headline metric from the preceding period to the requested one. A `*_pct_change` field is a signed relative change in a count, computed as `(current - previous) / previous`, so `0.5` means 50% higher and `-0.2` means 20% lower. It is null when the previous period's count was zero, because there is nothing to compute a relative change from. A `*_rate_pp` field is the signed difference between the two periods' rate values, each expressed as a fraction, so `0.012` means the rate rose by 1.2 percentage points and `-0.003` means it fell by 0.3 points. It is null when either period's rate is undefined, because its denominator was zero. `delivery_rate_pp` and `bounce_rate_pp` range from `-1` to `1`, because the rates behind them cannot exceed 1. The engagement deltas have no fixed bound, because events are counted when they arrive rather than when the message was sent, which can push their rate above 1.
4180
4289
  *
4181
4290
  */
4182
4291
  type EmailStatsComparisonDelta = {
@@ -4244,20 +4353,20 @@ type EmailStatsComparison = {
4244
4353
  readonly delta: EmailStatsComparisonDelta;
4245
4354
  };
4246
4355
  /**
4247
- * The window the server actually computed against. The summary serves two window grains: calendar days (bounds are YYYY-MM-DD) and hours (bounds are RFC 3339 instants). The grain of `from` and `to` mirrors the grain of the request's bounds; days and hour boundaries follow the requested `timezone` (UTC when omitted).
4356
+ * The window this response was actually computed against. The summary serves two window grains: calendar days (bounds are YYYY-MM-DD) and hours (bounds are RFC 3339 instants). The grain of `from` and `to` mirrors the grain of the request's bounds. Days and hour boundaries follow the requested `timezone` (UTC when omitted).
4248
4357
  *
4249
4358
  */
4250
4359
  type EmailStatsSummaryPeriod = {
4251
4360
  /**
4252
- * Inclusive start of the window the response covers. A calendar day (YYYY-MM-DD, in the requested `timezone`) for day windows; for hour windows, an RFC 3339 UTC instant marking the start of the first hour, which falls on a local hour boundary when `timezone` is set.
4361
+ * Inclusive start of the window the response covers. A calendar day (YYYY-MM-DD, in the requested `timezone`) for day windows. For hour windows, an RFC 3339 UTC instant marking the start of the first hour, which falls on a local hour boundary when `timezone` is set.
4253
4362
  */
4254
4363
  readonly from: string;
4255
4364
  /**
4256
- * Inclusive end of the window the response covers. A calendar day (YYYY-MM-DD, in the requested `timezone`) for day windows; for hour windows, an RFC 3339 UTC instant marking the start of the last hour, which falls on a local hour boundary when `timezone` is set.
4365
+ * Inclusive end of the window the response covers. A calendar day (YYYY-MM-DD, in the requested `timezone`) for day windows. For hour windows, an RFC 3339 UTC instant marking the start of the last hour, which falls on a local hour boundary when `timezone` is set.
4257
4366
  */
4258
4367
  readonly to: string;
4259
4368
  /**
4260
- * The instant the statistics in this response are current to: events recorded up to roughly this time are reflected, while more recent events may not be yet. Statistics are served from a rolling aggregation that refreshes every few seconds, so a response is near-real-time but not live; use this field to label data freshness (for example "as of 14:03") rather than assuming the numbers are to-the-second. Null when the freshness boundary is not being reported.
4369
+ * The instant the statistics in this response are current to: events recorded up to roughly this time are reflected, while more recent events may not be yet. Statistics are served from a rolling aggregation that refreshes every few seconds, so a response reflects data from up to a few seconds ago. Use this field to label data freshness (for example "as of 14:03") rather than assuming the numbers are to-the-second. Null when the freshness boundary is not being reported.
4261
4370
  *
4262
4371
  */
4263
4372
  readonly data_as_of?: string | null;
@@ -4275,7 +4384,7 @@ type EmailStatsTagsResponse = {
4275
4384
  */
4276
4385
  readonly data: Array<EmailTagStatsPoint>;
4277
4386
  /**
4278
- * Total number of distinct tags (name and value pairs) with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped; raise `limit` (up to 200) or narrow the window to see more.
4387
+ * Total number of distinct tags (name and value pairs) with activity in the period, regardless of `limit`. When it exceeds the number of rows returned, the ranking was capped. Raise `limit` (up to 200) or narrow the window to see more.
4279
4388
  *
4280
4389
  */
4281
4390
  readonly total: number;
@@ -4298,12 +4407,12 @@ type EmailTagStatsPoint = {
4298
4407
  readonly trend?: Array<EmailStatsSeriesPoint>;
4299
4408
  };
4300
4409
  /**
4301
- * Metric to rank breakdown rows by, applied descending. Shared by the breakdowns whose rows carry the full delivery, engagement, and latency block (tags, sending domains, categories, recipient domains, templates, broadcasts). Any count or rate may be used; rows whose rate is undefined (zero denominator) sort last. Bounce sub-types are addressed by their nested location in each row, for example `bounces.hard` and `bounces.hard_rate`.
4410
+ * Metric to rank breakdown rows by, applied descending. Shared by the breakdowns whose rows have the full delivery, engagement, and latency block: tags, sending domains, categories, recipient domains, templates, and broadcasts. Any count or rate can be used. A row whose rate is undefined, because its denominator was zero, sorts last. A bounce sub-type is nested under `bounces` in each row, so its sort name reflects that, for example `bounces.hard` and `bounces.hard_rate`.
4302
4411
  *
4303
4412
  */
4304
4413
  type EmailStatsSortMetric = "processed" | "delivered" | "bounced" | "complained" | "deferred" | "rejected" | "oob_bounces" | "bounces.hard" | "bounces.soft" | "bounces.admin" | "bounces.block" | "bounces.undetermined" | "opens" | "opens_non_prefetched" | "unique_opens" | "unique_opens_non_prefetched" | "clicks" | "unique_clicks" | "unsubscribes" | "delivery_rate" | "bounce_rate" | "complaint_rate" | "open_rate" | "click_rate" | "unsubscribe_rate" | "bounces.hard_rate" | "bounces.soft_rate" | "bounces.admin_rate" | "bounces.block_rate" | "bounces.undetermined_rate";
4305
4414
  /**
4306
- * Time-series stats payload. `period` echoes the range and bucket grain the server computed against; `data` is one row per bucket in chronological order.
4415
+ * Time-series stats payload. `period` echoes the range and bucket grain actually computed against. `data` is one row per bucket in chronological order.
4307
4416
  *
4308
4417
  */
4309
4418
  type EmailStatsResponse = {
@@ -4319,7 +4428,7 @@ type EmailStatsResponse = {
4319
4428
  */
4320
4429
  type EmailStatsPoint = {
4321
4430
  /**
4322
- * The day (YYYY-MM-DD, in the requested `timezone`) or hour this point covers, matching the period's grain. An hour bucket is an RFC 3339 UTC instant marking the start of the hour; it falls on a local hour boundary when `timezone` is set, which is on the UTC hour only for whole-hour offsets.
4431
+ * The day (YYYY-MM-DD, in the requested `timezone`) or hour this point covers, matching the period's grain. An hour bucket is an RFC 3339 UTC instant marking the start of the hour. It falls on a local hour boundary when `timezone` is set, which is on the UTC hour only for whole-hour offsets.
4323
4432
  */
4324
4433
  readonly bucket: string;
4325
4434
  /**
@@ -4337,17 +4446,18 @@ type WhatsAppEventList = {
4337
4446
  */
4338
4447
  data: Array<WhatsAppEvent>;
4339
4448
  };
4449
+ /**
4450
+ * Type of an event in a WhatsApp message's delivery timeline. `whatsapp.accepted`: Bird accepted the request. `whatsapp.sent`: handed to the WhatsApp network. `whatsapp.delivered`: delivery confirmed to the recipient's device. `whatsapp.read`: the recipient opened the message (this does not change the message `status`, which never becomes `read`). `whatsapp.failed`: terminal permanent failure. `whatsapp.rejected`: Bird refused the message before sending it, so it was never charged. `whatsapp.received`: an inbound message arrived from the contact. Open enum, new event types may be added over time, so treat any unrecognized value as a future event rather than an error. The values below are the types known at this version.
4451
+ *
4452
+ */
4453
+ type WhatsAppEventType$1 = "whatsapp.accepted" | "whatsapp.delivered" | "whatsapp.failed" | "whatsapp.read" | "whatsapp.rejected" | "whatsapp.sent" | (string & {});
4340
4454
  type WhatsAppEventId = string;
4341
4455
  type WhatsAppEvent = {
4342
4456
  /**
4343
4457
  * ID of the event (`ev_`-prefixed), unique within the message's timeline.
4344
4458
  */
4345
4459
  readonly id: WhatsAppEventId;
4346
- /**
4347
- * Lifecycle event type. `whatsapp.accepted`: Bird accepted the request. `whatsapp.sent`: handed to the WhatsApp network. `whatsapp.delivered`: delivery confirmed to the recipient's device. `whatsapp.read`: the recipient opened the message (this does not change the message `status`, which never becomes `read`). `whatsapp.failed`: terminal permanent failure. `whatsapp.rejected`: Bird refused the message before sending it, so it was never charged. `whatsapp.received`: an inbound message arrived from the contact. Open enum: new event types may be added over time, so treat any unrecognized value as a future event rather than an error.
4348
- *
4349
- */
4350
- readonly type: string;
4460
+ readonly type: WhatsAppEventType$1;
4351
4461
  /**
4352
4462
  * When this event occurred.
4353
4463
  */
@@ -4456,7 +4566,7 @@ type WhatsAppMessageTemplateComponent = {
4456
4566
  */
4457
4567
  type LanguageTag = string;
4458
4568
  /**
4459
- * A template's slug: its permanent, workspace-unique handle and API address. Lowercase letters, numbers, hyphens, and underscores. Fixed at creation, so anything that references it never breaks; the display name is the label to change freely.
4569
+ * A template's slug: what you send it by, for example `welcome-email`. You choose it when you create the template, and it cannot be changed afterwards. It can contain lowercase letters, numbers, hyphens, and underscores, has to start and end with a letter or a number, and can be up to 63 characters long.
4460
4570
  *
4461
4571
  */
4462
4572
  type TemplateSlug = string;
@@ -4467,11 +4577,11 @@ type WhatsAppTemplateSend = unknown & {
4467
4577
  */
4468
4578
  id?: WhatsAppTemplateId;
4469
4579
  /**
4470
- * The template to send, by its slug (for example `bird_otp`).
4580
+ * The template to send, by its slug handle (for example `bird_otp`).
4471
4581
  */
4472
4582
  slug?: TemplateSlug;
4473
4583
  /**
4474
- * Which of the template's languages to send, as a BCP-47 tag (for example `en` or `pt-BR`). Meta's underscore form (`pt_BR`) is accepted and normalized; the accepted message echoes the canonical BCP-47 form. May be omitted, in which case the template's default language is sent. A language the template is not stocked in returns a `422` that names the available tags.
4584
+ * Which of the template's languages to send, as a BCP-47 tag (for example `en` or `pt-BR`); Meta's underscore form (`pt_BR`) is accepted and normalized. Omit it to send the template's default language, unless the template sets `language_source_required`, in which case a send naming no language is rejected. When the template does not carry the language you ask for, its own `on_missing_language` setting decides whether the closest available language is sent instead or the send is rejected. The accepted message echoes the canonical BCP-47 form of the language it resolved to.
4475
4585
  *
4476
4586
  */
4477
4587
  language?: LanguageTag;
@@ -4661,6 +4771,316 @@ type VerificationOptions = {
4661
4771
  */
4662
4772
  channels?: Array<VerificationChannel$1>;
4663
4773
  };
4774
+ /**
4775
+ * What we can tell you about an email address: whether it will accept mail, how confident that is, why not when it will not, and what the address looks like it was meant to be when it looks misspelled.
4776
+ *
4777
+ * `result` is the field to decide on; `delivery_confidence` grades it, and `flags` describes the address itself rather than its deliverability, so a perfectly valid address can still have `role` or `disposable`.
4778
+ *
4779
+ * Fields with nothing behind them are left out rather than sent as null, so anything you can read in the response is something we actually resolved.
4780
+ *
4781
+ */
4782
+ type EmailLookup = {
4783
+ /**
4784
+ * The address that was looked up, exactly as you sent it.
4785
+ */
4786
+ readonly email: string;
4787
+ /**
4788
+ * Whether the address is well-formed and its domain is set up to receive mail at all. It says nothing about the mailbox itself, so a `valid` domain with no such mailbox is `true` here and `undeliverable` in `result`.
4789
+ */
4790
+ readonly valid: boolean;
4791
+ readonly result: EmailLookupResult$1;
4792
+ /**
4793
+ * How likely mail to this address is to be delivered, from 0 (certain not to be) to 100 (certain to be). Read it alongside `result` rather than instead of it, because the same score can sit under `neutral` or `risky` for different reasons.
4794
+ */
4795
+ readonly delivery_confidence: number;
4796
+ /**
4797
+ * Notable characteristics of the address. Empty when none apply.
4798
+ */
4799
+ readonly flags: Array<EmailLookupFlag$1>;
4800
+ /**
4801
+ * Why the address cannot receive mail. Absent unless `result` is `undeliverable`.
4802
+ */
4803
+ readonly reason?: EmailLookupReason$1;
4804
+ /**
4805
+ * The address this one looks like a misspelling of. Absent unless a correction was found, which in practice means `result` is `typo`. Offer it to whoever typed the original rather than sending to it unasked, because it is a guess and the address they meant may be neither one.
4806
+ */
4807
+ readonly did_you_mean?: string;
4808
+ };
4809
+ /**
4810
+ * Why an address cannot receive mail. `invalid_syntax` means the address is not a well-formed address at all, `invalid_domain` means the domain does not accept mail anywhere, and `invalid_recipient` means the domain accepts mail but this mailbox does not exist.
4811
+ *
4812
+ * Open enum: further reasons may be added over time, so treat an unrecognized value as a future one rather than an error. `result` is what to branch on; this field explains it.
4813
+ *
4814
+ */
4815
+ type EmailLookupReason$1 = "invalid_syntax" | "invalid_domain" | "invalid_recipient" | (string & {});
4816
+ /**
4817
+ * A notable characteristic of an email address. `role` means it addresses a function rather than a person (`support@`, `info@`), so replies and consent are ambiguous and complaints are more likely. `disposable` means it belongs to a throwaway-address provider and will stop existing. `free_provider` means it belongs to a consumer mailbox provider such as Gmail or Outlook.com, which is ordinary for consumer mail and a signal when you expected a business address.
4818
+ *
4819
+ * Open enum: more flags may be added over time, so treat an unrecognized value as a future flag rather than an error.
4820
+ *
4821
+ */
4822
+ type EmailLookupFlag$1 = "role" | "disposable" | "free_provider" | (string & {});
4823
+ /**
4824
+ * The verdict on the address, and the one field to decide on.
4825
+ *
4826
+ * `valid` means the address exists and accepts mail. `neutral` means it could not be confirmed either way, usually because the receiving domain answers every recipient the same. `risky` means it will probably accept the mail but is likelier than most to bounce or complain (a role, disposable, or low-reputation address). `undeliverable` means it will not accept mail, and `reason` says why. `typo` means the address looks like a misspelling of a real one, and `did_you_mean` has the correction.
4827
+ *
4828
+ * Open enum: further verdicts may be added over time, so treat an unrecognized value as a future one rather than an error. Branch on the values you know and fall back on `delivery_confidence`, which is always present and always comparable.
4829
+ *
4830
+ */
4831
+ type EmailLookupResult$1 = "valid" | "neutral" | "risky" | "undeliverable" | "typo" | (string & {});
4832
+ type EmailLookupRequest = {
4833
+ /**
4834
+ * The email address to look up. Send it exactly as you hold it: the part before the `@` is case-sensitive, so nothing is lowercased for you, and a display-name form such as `Aisha <aisha@example.com>` is rejected rather than unwrapped.
4835
+ *
4836
+ */
4837
+ email: string;
4838
+ };
4839
+ /**
4840
+ * What Bird knows about a phone number.
4841
+ *
4842
+ * The number, its flags and its line type are the free baseline and are always present; the country and the two networks join them whenever they could be identified. Each property you request through `type` comes back as a block of the same name, carrying its own `status`. A property you did not request is absent altogether, and a property that could not be answered is present with its `status` alone. You are billed for exactly the properties whose status is `ok`.
4843
+ *
4844
+ * Fields with nothing behind them are left out rather than sent as null, so anything you can read in the response is something Bird actually resolved.
4845
+ *
4846
+ */
4847
+ type PhoneNumberLookup = {
4848
+ /**
4849
+ * The number that was looked up, in E.164 format.
4850
+ */
4851
+ readonly phone_number: string;
4852
+ /**
4853
+ * The ISO 3166-1 alpha-2 country of the number. Absent when the number belongs to no single country, as a non-geographic range does.
4854
+ */
4855
+ readonly country_code?: CountryCode | null;
4856
+ /**
4857
+ * The network that serves the number today. Absent when no network could be identified.
4858
+ */
4859
+ readonly network_info?: LookupNetworkInfo | null;
4860
+ /**
4861
+ * The network that issued the number's range. It differs from `network_info` when the number has been ported. Absent when the issuing network could not be identified.
4862
+ */
4863
+ readonly original_network_info?: LookupNetworkInfo | null;
4864
+ /**
4865
+ * Notable characteristics of the number. Empty when none apply.
4866
+ */
4867
+ readonly flags: Array<LookupFlag$1>;
4868
+ readonly line_type: LookupLineType;
4869
+ /**
4870
+ * The allocated service of the number's range. Absent unless you requested the `classification` property.
4871
+ */
4872
+ readonly classification?: LookupClassification;
4873
+ /**
4874
+ * Whether the number is live on its network. Absent unless you requested the `presence` property.
4875
+ */
4876
+ readonly presence?: LookupPresence;
4877
+ /**
4878
+ * Whether the number is roaming. Absent unless you requested the `roaming` property.
4879
+ */
4880
+ readonly roaming?: LookupRoaming;
4881
+ /**
4882
+ * When the number's SIM last changed. Absent unless you requested the `sim_swap` property.
4883
+ */
4884
+ readonly sim_swap?: LookupSimSwap;
4885
+ /**
4886
+ * The number's porting record. Absent unless you requested the `porting` property.
4887
+ */
4888
+ readonly porting?: LookupPorting;
4889
+ /**
4890
+ * The number's credibility score. Absent unless you requested the `score` property.
4891
+ */
4892
+ readonly score?: LookupScore;
4893
+ };
4894
+ /**
4895
+ * A credibility score for the number. Returned when you request the `score` property.
4896
+ */
4897
+ type LookupScore = {
4898
+ readonly status: LookupPropertyStatus$1;
4899
+ /**
4900
+ * Credibility from 0 (low) to 100 (high). A low score means the number looks less credible than a typical subscriber line in the same range; it is a signal to weigh, not a verdict. It is a composite and is not derivable from the other properties. Present only when `status` is `ok`.
4901
+ *
4902
+ */
4903
+ readonly value?: number;
4904
+ };
4905
+ /**
4906
+ * How a requested property resolved.
4907
+ *
4908
+ * `ok` means the property was answered and its value is in the response.
4909
+ *
4910
+ * `unavailable` means no answer arrived, so the property adds nothing: its block is null, or for `classification`, `line_type` is left as the free baseline resolved it. The property is not billed.
4911
+ *
4912
+ * `inconclusive` means an answer arrived but does not resolve the property, either because the number is outside the coverage of the data behind it or because the answer is one we cannot yet place. It is a real answer rather than a missing one, and it is not billed either.
4913
+ *
4914
+ * Open enum: further statuses may be added over time, so treat an unrecognized value as a future one rather than an error. Only `ok` carries a value and only `ok` is billed, so branching on `ok` and treating everything else as "not answered" stays correct however the vocabulary grows.
4915
+ *
4916
+ */
4917
+ type LookupPropertyStatus$1 = "ok" | "unavailable" | "inconclusive" | (string & {});
4918
+ /**
4919
+ * One recorded move of a number between networks.
4920
+ */
4921
+ type LookupPortingEvent = {
4922
+ /**
4923
+ * When the move was recorded, null when the record carries no date.
4924
+ */
4925
+ readonly occurred_at: string | null;
4926
+ /**
4927
+ * What the record describes, as the number's registry reports it. Registries use their own short codes rather than a shared vocabulary, so treat this as a label to display rather than a value to branch on.
4928
+ */
4929
+ readonly action: string | null;
4930
+ };
4931
+ /**
4932
+ * Whether the number has ever moved network, when it last did, and its full porting record. Returned when you request the `porting` property; the baseline only reports whether a number has ever ported, through the `ported` flag.
4933
+ *
4934
+ */
4935
+ type LookupPorting = {
4936
+ readonly status: LookupPropertyStatus$1;
4937
+ /**
4938
+ * Whether the number has ever moved network. False is a positive finding rather than a lack of one: the registry was consulted and holds no move for this number. Present only when `status` is `ok`.
4939
+ *
4940
+ */
4941
+ readonly ported?: boolean;
4942
+ /**
4943
+ * When the number last moved network. Absent when it has never ported or when no date is on record.
4944
+ */
4945
+ readonly last_ported_at?: string | null;
4946
+ /**
4947
+ * Whether `last_ported_at` is an approximation. Some registries record only the period a move happened in, not the day.
4948
+ */
4949
+ readonly last_ported_at_is_approximate?: boolean;
4950
+ /**
4951
+ * Every move on record, oldest first. Absent when the number has never ported or when its registry publishes no history.
4952
+ */
4953
+ readonly history?: Array<LookupPortingEvent>;
4954
+ };
4955
+ /**
4956
+ * When the number's SIM last changed. Returned when you request the `sim_swap` property.
4957
+ */
4958
+ type LookupSimSwap = {
4959
+ readonly status: LookupPropertyStatus$1;
4960
+ /**
4961
+ * When the SIM was last changed. Absent when only a recency band is known.
4962
+ */
4963
+ readonly last_swapped_at?: string | null;
4964
+ /**
4965
+ * The lower bound, in days, of how long ago the SIM was last changed. Networks that do not release an exact date report a band instead; absent when no lower bound is known.
4966
+ */
4967
+ readonly min_days?: number | null;
4968
+ /**
4969
+ * The upper bound, in days, of how long ago the SIM was last changed. Absent when no upper bound is known; with a lower bound present, that means the change was at least `min_days` ago.
4970
+ */
4971
+ readonly max_days?: number | null;
4972
+ };
4973
+ /**
4974
+ * Whether the number is roaming, and on which network. Returned when you request the `roaming` property.
4975
+ */
4976
+ type LookupRoaming = {
4977
+ readonly status: LookupPropertyStatus$1;
4978
+ /**
4979
+ * Whether the number is currently roaming outside its home network. Present only when `status` is `ok`.
4980
+ */
4981
+ readonly is_roaming?: boolean;
4982
+ /**
4983
+ * The mobile country code of the visited network. Absent when the number is not roaming or the visited network is not reported.
4984
+ */
4985
+ readonly mcc?: string | null;
4986
+ /**
4987
+ * The mobile network code of the visited network. Absent when the number is not roaming or the visited network is not reported.
4988
+ */
4989
+ readonly mnc?: string | null;
4990
+ };
4991
+ /**
4992
+ * Whether the number is live on its network right now. Returned when you request the `presence` property.
4993
+ *
4994
+ * This is the one property no database can answer: it is a real-time query to the network the number is registered on.
4995
+ *
4996
+ */
4997
+ type LookupPresence = {
4998
+ readonly status: LookupPropertyStatus$1;
4999
+ /**
5000
+ * Whether the number is registered on a network and able to receive traffic. False means the network answered and reported the number as not currently reachable, which is different from us being unable to find out. Present only when `status` is `ok`.
5001
+ *
5002
+ */
5003
+ readonly reachable?: boolean;
5004
+ };
5005
+ /**
5006
+ * The allocated service of the number's range, at the precision the intelligence source publishes it.
5007
+ *
5008
+ * This is a finer vocabulary than `line_type`, which reports what the carrier platform alone can tell. Eleven of these values have no carrier equivalent at all: a number the carrier can only call `service` may be `premium_rate`, `shared_cost`, `universal_access` or a voicemail platform, and those carry very different cost and fraud implications. Where the two fields do overlap, they are two independent opinions rather than one refining the other.
5009
+ *
5010
+ */
5011
+ type LookupClassificationValue = "mobile" | "fixed_line" | "fixed_line_or_mobile" | "voip" | "toll_free" | "premium_rate" | "shared_cost" | "local_rate" | "national_rate" | "personal_number" | "universal_access" | "satellite" | "pager" | "payphone" | "m2m" | "isp" | "vpn" | "voice_mail" | "calling_cards" | "short_codes" | "service" | "other";
5012
+ /**
5013
+ * The allocated service of the number's range. Returned when you request the `classification` property.
5014
+ *
5015
+ * This sits beside `line_type` rather than replacing it, so you can always see which source answered: `line_type` is what the carrier platform reports and costs nothing, `classification` is what the intelligence source reports and is what you paid for.
5016
+ *
5017
+ */
5018
+ type LookupClassification = {
5019
+ readonly status: LookupPropertyStatus$1;
5020
+ /**
5021
+ * The allocated service of the range. Present only when `status` is `ok`.
5022
+ */
5023
+ readonly value?: LookupClassificationValue;
5024
+ };
5025
+ /**
5026
+ * What kind of line the number is, as reported by the carrier platform.
5027
+ *
5028
+ * This is part of the free baseline and is returned on every lookup, whatever you request. It never changes with what you buy. `unknown` means the carrier platform holds no classification for the range, and `other` means it holds one that has no equivalent here.
5029
+ *
5030
+ * For the allocated service of the range at finer precision, request the `classification` property. That answers from a different source, with its own wider vocabulary, and is reported separately so you can always tell the two apart.
5031
+ *
5032
+ */
5033
+ type LookupLineType = "mobile" | "fixed_line" | "voip" | "toll_free" | "premium_rate" | "satellite" | "pager" | "payphone" | "m2m" | "service" | "other" | "unknown";
5034
+ /**
5035
+ * A notable characteristic of a number. `ported` means the number has moved from the network that issued it to another one, so `network_info` and `original_network_info` name different carriers.
5036
+ *
5037
+ * Open enum: more flags may be added over time, so treat an unrecognized value as a future flag rather than an error.
5038
+ *
5039
+ */
5040
+ type LookupFlag$1 = "ported" | (string & {});
5041
+ /**
5042
+ * The network a number belongs to.
5043
+ */
5044
+ type LookupNetworkInfo = {
5045
+ /**
5046
+ * The carrier's name, absent when the carrier could not be identified.
5047
+ */
5048
+ readonly carrier_name?: string | null;
5049
+ /**
5050
+ * The mobile country code, absent for a network that has none or could not be identified.
5051
+ */
5052
+ readonly mcc?: string | null;
5053
+ /**
5054
+ * The mobile network code, absent for a network that has none or could not be identified.
5055
+ */
5056
+ readonly mnc?: string | null;
5057
+ };
5058
+ /**
5059
+ * ISO 3166-1 alpha-2 country code.
5060
+ */
5061
+ type CountryCode = string;
5062
+ type PhoneNumberLookupRequest = {
5063
+ /**
5064
+ * The phone number to look up, in international format: the country calling code, then the national number. The leading `+` is optional, and `00` works in its place, so `+31612345678`, `31612345678` and `0031612345678` are all the same number. A number written for dialling inside one country, with no country code, is rejected rather than guessed at.
5065
+ */
5066
+ phone_number: string;
5067
+ /**
5068
+ * The paid properties to enrich the answer with. Omit it, or send an empty array, to get the free baseline and make no vendor call.
5069
+ *
5070
+ * Each delivered property is billed on top of the lookup itself. A property that could not be answered is reported in `properties` and is not billed.
5071
+ *
5072
+ */
5073
+ type?: Array<LookupProperty>;
5074
+ };
5075
+ /**
5076
+ * An intelligence property you can buy for a number, beyond the free baseline.
5077
+ *
5078
+ * `classification` resolves `line_type` to its precise allocated service (premium rate, satellite, machine-to-machine, payphone) where the baseline only distinguishes broad categories. `porting` returns when the number last moved network and its full porting record. `presence` reports whether the number is live on the network right now. `roaming` reports whether it is roaming and on which network. `sim_swap` returns when its SIM last changed. `score` returns a credibility score from 0 to 100.
5079
+ *
5080
+ * Each property you request is billed separately, and only when it is delivered.
5081
+ *
5082
+ */
5083
+ type LookupProperty = "classification" | "porting" | "presence" | "roaming" | "sim_swap" | "score";
4664
5084
  /**
4665
5085
  * Bucket grain for a stats trend series.
4666
5086
  */
@@ -4673,30 +5093,65 @@ type SmsTemplateList = {
4673
5093
  };
4674
5094
  type SmsTemplateVersionId = string;
4675
5095
  /**
4676
- * A single variable slot a template fills in from the values supplied when sending. Shared across channels (SMS, email) so template introspection reads the same everywhere.
5096
+ * What a send or a preview does when it asks for a language the template
5097
+ * cannot serve.
5098
+ *
5099
+ * `fallback` serves the closest match instead. It tries a broader form of the
5100
+ * same language first, so a request for `pt-BR` can be served by a stocked
5101
+ * `pt`, and then the template's default language. A send never fails because a
5102
+ * language is missing.
5103
+ *
5104
+ * `fail` rejects the send rather than serving a different language, for content
5105
+ * where sending the wrong language is worse than not sending at all. It matches
5106
+ * the requested tag or a broader form of it and refuses a sibling variant, so
5107
+ * `pt-BR` is never served by `pt-PT`. A send that names no language still uses
5108
+ * the default language.
5109
+ *
5110
+ * The default is per channel and stated on each channel's own field, because
5111
+ * what a wrong-language send costs differs: where every language is separately
5112
+ * reviewed and separately priced, falling back silently would send content the
5113
+ * recipient did not expect at a rate the sender did not choose.
5114
+ *
5115
+ */
5116
+ type TemplateOnMissingLanguage = "fallback" | "fail";
5117
+ /**
5118
+ * Where one language of a template stands, on a channel whose content Bird publishes directly. `live` is what sends serve today. `draft` is a language the draft carries that has never been published. `superseded` is a language a later version replaced. Open enum: treat an unrecognised value as not sendable.
5119
+ *
5120
+ */
5121
+ type TemplateLanguageStatus$1 = "draft" | "live" | "superseded" | (string & {});
5122
+ /**
5123
+ * One language's state on a template: whether it is live for sends. Content is not here; the template carries the body of its default language, and a send resolves the rest.
5124
+ *
5125
+ */
5126
+ type SmsTemplateLanguageState = {
5127
+ status: TemplateLanguageStatus$1;
5128
+ };
5129
+ /**
5130
+ * A single variable slot a template fills in from the values supplied when sending. The same shape on email, SMS and WhatsApp, so reading what a template needs works the same way whichever channel you are sending on.
4677
5131
  *
4678
5132
  */
4679
5133
  type TemplateVariable = {
4680
5134
  /**
4681
- * The parameter key this slot is filled with.
5135
+ * The key this slot is filled by. On email and SMS it is the key you set in the send's `parameters` object. On WhatsApp it is the `name` you repeat on the matching parameter inside `components`, or, for a template whose placeholders are positional, the position itself as `1`, `2` and so on.
5136
+ *
4682
5137
  */
4683
5138
  readonly key: string;
4684
5139
  /**
4685
- * The value type this slot accepts. Open enum treat any unrecognized value as a future type rather than an error. SMS templates use the typed slots (`code`, `amount`, …); email templates use `text`.
5140
+ * The value type this slot accepts. SMS templates use the typed slots (`code`, `amount` and the rest), each of which rejects a value that does not match its `constraint`. Email and WhatsApp templates use `text`, which accepts any value. Open enum: treat an unrecognized value as a future type rather than an error.
4686
5141
  *
4687
5142
  */
4688
5143
  readonly type: string;
4689
5144
  /**
4690
- * Whether the slot must be supplied when sending. A send that leaves a required slot unset is rejected.
5145
+ * Whether the slot must be supplied when sending. On SMS and WhatsApp a missing required value is rejected with a `422`. On email it is advisory: a missing value renders as empty rather than rejecting the send.
4691
5146
  *
4692
5147
  */
4693
5148
  readonly required: boolean;
4694
5149
  /**
4695
- * A human-readable description of the accepted values.
5150
+ * A plain-language description of what values this variable accepts.
4696
5151
  */
4697
5152
  readonly constraint: string;
4698
5153
  /**
4699
- * Whether this slot's value is redacted before it reaches storage. A sensitive slot's rendered value never appears in message content read back through the API: a stand-in placeholder is stored instead.
5154
+ * Whether this slot's value is kept out of durable storage. A sensitive slot's rendered value never appears in message content read back through the API: a stand-in placeholder is stored instead.
4700
5155
  *
4701
5156
  */
4702
5157
  readonly sensitive?: boolean;
@@ -4706,69 +5161,134 @@ type TemplateVariable = {
4706
5161
  */
4707
5162
  type SmsMessageCategory = "transactional" | "marketing" | "authentication" | "service";
4708
5163
  /**
4709
- * Whether the template is a built-in Bird template (`system`) or one your workspace authored (`workspace`).
5164
+ * Where the template stands as a whole. The same five states on every channel.
5165
+ *
5166
+ * - `draft`: nothing has ever gone live.
5167
+ * - `pending`: nothing is live and at least one language is in review.
5168
+ * - `active`: at least one language is live, so something can be sent.
5169
+ * - `rejected`: it was reviewed and every language was refused.
5170
+ * - `inactive`: nothing is live and nothing is in review, so content was withdrawn or was blocked before anything went live.
5171
+ *
5172
+ * This is a summary. It answers whether the template is usable at all, not
5173
+ * whether every language is: a template with one language live is `active` even
5174
+ * while another is still drafted or refused. Read `languages` for per-language
5175
+ * state, which is what says which language is where and why.
5176
+ *
5177
+ * Which of the five a template can reach follows its channel's review model. A
5178
+ * channel whose content a third party reviews reaches all five; one whose
5179
+ * content goes live on publish moves between `draft`, `active` and `inactive`.
5180
+ *
5181
+ * Open enum: treat a value you do not recognize as a new one rather than as
5182
+ * an error.
5183
+ *
5184
+ */
5185
+ type TemplateStatus$1 = "draft" | "pending" | "active" | "rejected" | "inactive" | (string & {});
5186
+ /**
5187
+ * Whether the template is one of our built-in templates (`system`) or one your workspace created (`workspace`).
4710
5188
  */
4711
5189
  type TemplateScope = "system" | "workspace";
5190
+ type SmsTemplateId = string;
4712
5191
  /**
4713
- * A template's send-by handle the stable reference used in place of the template id when sending. Lowercase letters, numbers, hyphens, and underscores; starts and ends with a letter or number.
5192
+ * A message template: one identity holding a copy of the message per language, resolved to one at send. It declares the variable slots a send fills in, so the parts that change travel with the request and the wording does not.
4714
5193
  *
4715
5194
  */
4716
- type TemplateName = string;
4717
- type SmsTemplateId = string;
4718
5195
  type SmsTemplate = {
4719
5196
  /**
4720
5197
  * Unique identifier for the template.
4721
5198
  */
4722
5199
  readonly id: SmsTemplateId;
4723
5200
  /**
4724
- * The template's stable handle. Pass it (or the id) as the template reference when sending.
5201
+ * The template's permanent handle. Pass it (or the id) as the template reference when sending. Handles beginning with `bird_` are reserved for Bird's built-in templates.
5202
+ *
4725
5203
  */
4726
- readonly name: TemplateName;
5204
+ readonly slug: TemplateSlug;
4727
5205
  /**
4728
- * Human-readable description of what the template is for.
5206
+ * The template's display name, shown wherever the template is listed. Nothing resolves through it, so it is safe to show wherever a human reads the template.
5207
+ *
4729
5208
  */
4730
- readonly description: string;
5209
+ readonly name: string;
5210
+ /**
5211
+ * What the template is for. Null when unset.
5212
+ */
5213
+ readonly description: string | null;
4731
5214
  scope: TemplateScope;
5215
+ status: TemplateStatus$1;
4732
5216
  /**
4733
5217
  * Content classification applied to messages sent from this template.
4734
5218
  */
4735
5219
  readonly category: SmsMessageCategory;
4736
5220
  /**
4737
- * The template body in its default language, shown for preview. Variable placeholders appear inline (for example `{{ code }}`).
5221
+ * The template body in its default language, shown for preview. Variable placeholders appear inline (for example `{{ code }}`). Name a `language` on the send to have another one served.
4738
5222
  *
4739
5223
  */
4740
5224
  readonly body: string;
4741
5225
  /**
4742
- * The typed slots this template fills in from the values you supply when sending.
5226
+ * The typed slots this template fills in from the values you supply in `parameters` when sending. Every language of a template declares the same slots, so this list holds for whichever one a send resolves to.
5227
+ *
4743
5228
  */
4744
5229
  readonly variables: Array<TemplateVariable>;
4745
5230
  /**
4746
- * The languages this template is available in, as BCP-47 tags.
5231
+ * The language a send uses when it names none, and the last resort when `on_missing_language` is `fallback` and the language asked for is not available.
5232
+ *
5233
+ */
5234
+ readonly default_language: LanguageTag;
5235
+ /**
5236
+ * The languages a send can resolve right now, as BCP-47 tags. The set may shrink for reasons other than editing, so read it rather than assuming it matches what you last saw.
5237
+ *
5238
+ */
5239
+ readonly available_languages: Array<LanguageTag>;
5240
+ /**
5241
+ * Where each of the template's languages stands, keyed by BCP-47 language tag. Content is not here: `body` previews the default language, and a send resolves the one it needs.
5242
+ *
4747
5243
  */
4748
- readonly available_languages: Array<string>;
5244
+ readonly languages: {
5245
+ [key: string]: SmsTemplateLanguageState;
5246
+ };
4749
5247
  /**
4750
- * The template's lifecycle state. `active` means the template can be sent; every built-in Bird template is `active`. `draft` (being edited), `pending` (submitted for review), `approved` (passed review), and `rejected` (failed review) describe a workspace-authored template's authoring lifecycle; workspace-authored SMS templates are not available yet, so today every template is `active`.
5248
+ * What a send does when it asks for a language this template does not carry. Defaults to `fallback` on SMS.
4751
5249
  *
4752
5250
  */
4753
- readonly status: "active" | "draft" | "pending" | "approved" | "rejected";
5251
+ readonly on_missing_language: TemplateOnMissingLanguage;
4754
5252
  /**
4755
- * The current editable draft version. Always null today: SMS templates are not yet versioned; present for parity with email templates.
5253
+ * Whether a send has to name a language. When true, a send that names none is rejected instead of being served the default language.
5254
+ *
5255
+ */
5256
+ readonly language_source_required: boolean;
5257
+ /**
5258
+ * The current editable draft version, or null for a built-in `system` template, which has no draft.
5259
+ *
4756
5260
  */
4757
5261
  readonly draft_version_id: SmsTemplateVersionId | null;
4758
5262
  /**
4759
- * The currently published version, or null if the template has never been published. Always null today: SMS templates are not yet versioned; present for parity with email templates.
5263
+ * The version a send resolves to, or null for a built-in `system` template, which Bird ships ready to send rather than versioning.
5264
+ *
4760
5265
  */
4761
- readonly published_version_id?: SmsTemplateVersionId | null;
5266
+ readonly live_version_id: SmsTemplateVersionId | null;
4762
5267
  /**
4763
- * The draft's revision counter. Always null today: SMS templates are not yet versioned; present for parity with email templates.
5268
+ * Deprecated: use `live_version_id` instead, which carries the same value.
5269
+ *
5270
+ *
5271
+ * @deprecated
5272
+ */
5273
+ readonly published_version_id: SmsTemplateVersionId | null;
5274
+ /**
5275
+ * The draft's revision counter. Null for a built-in `system` template, which is unversioned.
5276
+ *
4764
5277
  */
4765
5278
  readonly revision: number | null;
4766
5279
  /**
4767
- * When the template was created. Null for built-in templates.
5280
+ * When this template was last submitted. Null for a built-in `system` template: Bird ships it ready to send, so there is nothing submitted to date.
5281
+ *
5282
+ */
5283
+ readonly last_submitted_at: string | null;
5284
+ /**
5285
+ * When the template was created. Null for a built-in `system` template, which Bird ships rather than stores.
5286
+ *
4768
5287
  */
4769
5288
  readonly created_at: string | null;
4770
5289
  /**
4771
- * When the template was last updated. Null for built-in templates.
5290
+ * When the template was last modified. Null for a built-in `system` template, which Bird ships rather than stores.
5291
+ *
4772
5292
  */
4773
5293
  readonly updated_at: string | null;
4774
5294
  };
@@ -4900,12 +5420,19 @@ type SmsTemplateSend = unknown & {
4900
5420
  */
4901
5421
  id?: SmsTemplateId;
4902
5422
  /**
4903
- * The template to send, by its name handle (for example `bird_otp_verification`). Browse the available templates and their variables with the templates endpoint.
5423
+ * The template to send, by its slug handle (for example `bird_otp_verification`). Browse the available templates and their variables with the templates endpoint.
4904
5424
  *
4905
5425
  */
4906
- name?: TemplateName;
5426
+ slug?: TemplateSlug;
4907
5427
  /**
4908
- * Which of the template's localized bodies to send, as a BCP-47 tag. Falls back to the closest available language, then English, when the exact tag is not stocked. Omit for English.
5428
+ * Deprecated: use `slug` instead. Resolved as a slug first, and only if that finds nothing, matched against the template's display name.
5429
+ *
5430
+ *
5431
+ * @deprecated
5432
+ */
5433
+ name?: string;
5434
+ /**
5435
+ * Which of the template's languages to send. Omit it to send the template's default language, unless the template sets `language_source_required`, in which case a send naming no language is rejected. When the template does not carry the language you ask for, its own `on_missing_language` setting decides whether the closest available language is sent instead or the send is rejected.
4909
5436
  *
4910
5437
  */
4911
5438
  language?: LanguageTag;
@@ -4942,7 +5469,8 @@ type SmsSendOptions = {
4942
5469
  };
4943
5470
  type SmsMessageSendRequest = unknown & {
4944
5471
  /**
4945
- * Recipient phone number in E.164 format (for example `+15551234567`). One recipient per message.
5472
+ * Recipient phone number in E.164 format (for example `+14155550100`). One recipient per message. The number is stored and returned in canonical E.164; a recipient that cannot be routed returns a `422` `SMSInvalidRecipient`.
5473
+ *
4946
5474
  */
4947
5475
  to: string;
4948
5476
  /**
@@ -5032,13 +5560,13 @@ type SmsMessageSendRequest = unknown & {
5032
5560
  type MessageDirection = "outbound" | "inbound";
5033
5561
  type AudienceContactsRemoveRequest = {
5034
5562
  /**
5035
- * Contacts to remove from the audience. Removing a contact that is not a member has no effect; duplicate IDs in the list are collapsed. If any ID does not exist in the workspace, the whole request fails with a validation error and no memberships are removed.
5563
+ * Contacts to remove from the audience. Removing a contact that is not a member has no effect. Duplicate IDs in the list are collapsed. If any ID does not exist in the workspace, the whole request fails with a validation error and no memberships are removed.
5036
5564
  */
5037
5565
  contact_ids: Array<ContactId>;
5038
5566
  };
5039
5567
  type AudienceContactsAddRequest = {
5040
5568
  /**
5041
- * Contacts to add to the audience. Adding a contact that is already a member has no effect and keeps its original join time; duplicate IDs in the list are collapsed. If any ID does not exist in the workspace, the whole request fails with a validation error and no contacts are added.
5569
+ * Contacts to add to the audience. Adding a contact that is already a member has no effect and keeps its original join time. Duplicate IDs in the list are collapsed. If any ID does not exist in the workspace, the whole request fails with a validation error and no contacts are added.
5042
5570
  */
5043
5571
  contact_ids: Array<ContactId>;
5044
5572
  };
@@ -5106,7 +5634,7 @@ type AudienceMember = {
5106
5634
  };
5107
5635
  type AudienceUpdateRequest = {
5108
5636
  /**
5109
- * New display name for the audience. Omit to keep the current name; the name cannot be cleared, and a whitespace-only value returns a validation error.
5637
+ * New display name for the audience. Omit to keep the current name. The name cannot be cleared, and a whitespace-only value returns a validation error.
5110
5638
  */
5111
5639
  name?: string;
5112
5640
  /**
@@ -5124,10 +5652,9 @@ type AudienceCreateRequest = {
5124
5652
  */
5125
5653
  description?: string;
5126
5654
  /**
5127
- * How the audience's recipients are determined. `static` (the default) is an explicit member list you manage via the API. `dynamic` and `external` are preview values and currently unavailable; creating an audience with either returns a validation error.
5128
- *
5655
+ * How the audience's recipients are determined. `static` is an explicit member list you manage by adding and removing contacts.
5129
5656
  */
5130
- type?: "static" | "dynamic" | "external";
5657
+ type?: "static";
5131
5658
  };
5132
5659
  type ContactPropertyUpdateRequest = {
5133
5660
  /**
@@ -5187,10 +5714,9 @@ type Audience = {
5187
5714
  */
5188
5715
  description?: string | null;
5189
5716
  /**
5190
- * How the audience's recipients are determined. `static` (the default) is an explicit member list you manage via the API. `dynamic` and `external` are preview values and currently unavailable; creating an audience with either returns a validation error.
5191
- *
5717
+ * How the audience's recipients are determined. `static` is an explicit member list you manage by adding and removing contacts.
5192
5718
  */
5193
- type: "static" | "dynamic" | "external";
5719
+ type: "static";
5194
5720
  } & Timestamps;
5195
5721
  type ContactUpdateRequest = {
5196
5722
  /**
@@ -5364,7 +5890,7 @@ type EmailMessageBatchItem = {
5364
5890
  */
5365
5891
  readonly requested_language?: LanguageTag | null;
5366
5892
  /**
5367
- * The template language this item was actually delivered in, in canonical form. Null when the item used no template. A value here differing from `requested_language` means the template did not carry the language asked for and its `on_missing_language` policy chose this one.
5893
+ * The template language this item was actually delivered in, in canonical form. Null when the item used no template. A value here differing from `requested_language` means the template did not have the language asked for and its `on_missing_language` policy chose this one.
5368
5894
  *
5369
5895
  */
5370
5896
  readonly resolved_language?: LanguageTag | null;
@@ -5394,12 +5920,16 @@ type EmailTemplateSend = unknown & {
5394
5920
  */
5395
5921
  slug?: TemplateSlug;
5396
5922
  /**
5397
- * Which of the template's languages to send. Omit it to send the template's default language, unless the template sets `language_source_required`, in which case a send naming no language is rejected. When the template does not carry the language you ask for, its own `on_missing_language` setting decides whether the closest available language is sent instead or the send is rejected.
5923
+ * Which of the template's languages to send. Omit it to send the template's default language, unless the template sets `language_source_required`, in which case a send naming no language is rejected. When the template does not have the language you ask for, its own `on_missing_language` setting decides whether the closest available language is sent instead or the send is rejected.
5398
5924
  *
5399
5925
  */
5400
5926
  language?: LanguageTag;
5401
5927
  /**
5402
- * Values for the template's parameters, keyed by parameter name. A parameter name is a single word, and every parameter the template's `variables` lists needs a value here: a send that omits one is rejected rather than delivered with a blank. Send everything `variables` lists rather than only what you expect the chosen language to use, since languages need not reference the same parameters and a value no language uses is ignored. Cap: 16 KB serialized.
5928
+ * Values for the template's variables, keyed by the variable name. A variable name is a single word.
5929
+ *
5930
+ * Every variable the template's `variables` lists needs a value here. A send that leaves one out is rejected rather than delivered with a blank in it. Send values for everything in that list rather than only what you expect the language you are sending to use, because languages do not have to use the same variables and a value no language uses is simply ignored.
5931
+ *
5932
+ * `bird` is reserved for the values we fill in ourselves, so a send that sets it is rejected. `parameters` is capped at 16 KB once serialized.
5403
5933
  *
5404
5934
  */
5405
5935
  parameters?: {
@@ -5408,23 +5938,23 @@ type EmailTemplateSend = unknown & {
5408
5938
  };
5409
5939
  type EmailMessageSendRequest = {
5410
5940
  /**
5411
- * 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.
5941
+ * Sender address, as a plain email string, an RFC 5322 mailbox string (`Jane <jane@acme.com>`), or an object with an optional display name. Must be from a verified domain in this workspace.
5412
5942
  */
5413
5943
  from: EmailAddressInput;
5414
5944
  /**
5415
- * 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.
5945
+ * Primary recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@acme.com>`), or an object with an optional display name.
5416
5946
  */
5417
5947
  to: Array<EmailAddressInput>;
5418
5948
  /**
5419
- * 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.
5949
+ * CC recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@acme.com>`), or an object with an optional display name.
5420
5950
  */
5421
5951
  cc?: Array<EmailAddressInput>;
5422
5952
  /**
5423
- * 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.
5953
+ * BCC recipients. Each entry is a plain email string, an RFC 5322 mailbox string (`Jane <jane@acme.com>`), or an object with an optional display name.
5424
5954
  */
5425
5955
  bcc?: Array<EmailAddressInput>;
5426
5956
  /**
5427
- * Message subject line. Required for inline sends; omit it when sending a `template` (the template supplies the subject).
5957
+ * Message subject line. Required for inline sends. Omit it when sending a `template` (the template supplies the subject).
5428
5958
  */
5429
5959
  subject?: string;
5430
5960
  /**
@@ -5436,24 +5966,30 @@ type EmailMessageSendRequest = {
5436
5966
  */
5437
5967
  text?: string;
5438
5968
  /**
5439
- * 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.
5969
+ * 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 header sizes that some receiving mail servers reject.
5440
5970
  *
5441
5971
  */
5442
5972
  reply_to?: Array<EmailAddressInput>;
5443
5973
  /**
5444
- * Custom email headers as key-value pairs (for example `References`, `In-Reply-To`, or your own `X-*` headers). Reserved headers are rejected with a `422`: set the message's addressing and subject through the dedicated fields (`from`, `to`, `cc`, `bcc`, `reply_to`, `subject`) rather than here, and headers the platform generates for you `Content-Type`, `Content-Transfer-Encoding`, `DKIM-Signature`, `Received`, and `Return-Path` cannot be overridden. `List-Unsubscribe` and `List-Unsubscribe-Post` are honored as-is on `transactional` sends; on `marketing` sends the platform sets a compliant unsubscribe header for you, so supplying them there is rejected with a `422`. Header values may not contain carriage-return or line-feed characters.
5974
+ * Custom email headers as key-value pairs (for example `References`, `In-Reply-To`, or your own `X-*` headers). Reserved headers are rejected with a `422`. Set the message's addressing and subject through the dedicated fields (`from`, `to`, `cc`, `bcc`, `reply_to`, `subject`) rather than here, and the headers generated for you automatically (`Content-Type`, `Content-Transfer-Encoding`, `DKIM-Signature`, `Received`, and `Return-Path`) cannot be overridden. `List-Unsubscribe` and `List-Unsubscribe-Post` are honored as-is on `transactional` sends. On a `marketing` send a compliant unsubscribe header is set for you, so supplying either one there is rejected with a `422`. Header values may not contain carriage-return or line-feed characters. Up to 25 headers per send, each value up to 998 characters.
5445
5975
  *
5446
5976
  */
5447
5977
  headers?: {
5448
5978
  [key: string]: string;
5449
5979
  };
5450
5980
  /**
5451
- * 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.
5981
+ * Structured `{name, value}` labels for **filtering and analytics**. Tags become first-class query dimensions:
5982
+ *
5983
+ * - Filter the list endpoint by tag name.
5984
+ * - Slice analytics rollups by tag.
5985
+ * - Surface in webhook payloads.
5986
+ *
5987
+ * 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.
5452
5988
  *
5453
5989
  */
5454
5990
  tags?: Array<Tag>;
5455
5991
  /**
5456
- * 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.
5992
+ * Arbitrary JSON object **stored, returned on API reads, and echoed in webhook payloads**. Path-queryable in analytics (for example, 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.
5457
5993
  *
5458
5994
  */
5459
5995
  metadata?: {
@@ -5467,7 +6003,7 @@ type EmailMessageSendRequest = {
5467
6003
  [key: string]: unknown;
5468
6004
  };
5469
6005
  /**
5470
- * Send a stored template instead of inline content. When set, omit `subject`/`html`/`text` the template supplies them; personalize with `template.parameters`.
6006
+ * Send a stored template instead of inline content. When set, omit `subject`, `html` and `text`, because the template supplies them. Personalize with `template.parameters`. A template send goes out immediately: `template` and `scheduled_at` are mutually exclusive, and combining them is rejected with a `422`.
5471
6007
  *
5472
6008
  */
5473
6009
  template?: EmailTemplateSend;
@@ -5485,37 +6021,29 @@ type EmailMessageSendRequest = {
5485
6021
  */
5486
6022
  ip_pool_id?: string;
5487
6023
  /**
5488
- * Content classification. Controls suppression policy: `marketing` blocks on all suppression reasons; `transactional` allows delivery through complaint and unsubscribe suppressions, for receipts, password resets, and similar operational mail. When you send with `template` and omit this field, the message takes the template's own classification, so a template created as `transactional` sends as transactional. Set this field to classify a single send differently from its template; it always takes precedence. Sends that carry no template and no category are `marketing`.
6024
+ * Content classification, which controls suppression policy:
6025
+ *
6026
+ * - `marketing`: Blocks on all suppression reasons.
6027
+ * - `transactional`: Allows delivery through complaint and unsubscribe suppressions, for receipts, password resets, and similar operational mail.
6028
+ *
6029
+ * When you send with `template` and omit this field, the message takes the template's own classification, so a template created as `transactional` sends as transactional. Set this field to classify a single send differently from its template. It always takes precedence. A send with no template and no category defaults to `marketing`.
5489
6030
  *
5490
6031
  */
5491
6032
  category?: EmailMessageCategory;
5492
6033
  /**
5493
- * Preview feature threaded replies. Currently unavailable; supplying this field returns `422 UnsupportedEmailFeature`. When generally available, sets In-Reply-To and References headers automatically.
5494
- */
5495
- in_reply_to_message_id?: EmailId;
5496
- /**
5497
- * File attachments. Bird rejects sends whose estimated generated message size exceeds 20 MB. The estimate is the HTML and text body plus all attachments and inline images measured after base64 encoding. Keep total raw attachment content at or below 15 MB for reliable headroom. In batch sends, this per-message cap still applies and the serialized JSON request body for the whole batch has a hard 20 MB cap. See the EmailAttachment schema for the full field contract.
6034
+ * Files to attach, up to 20 per message. A message can be at most 20 MB once it has been generated, and we refuse a send that would go over. That figure covers the HTML body, the text body and every attachment and inline image, all measured after base64 encoding, which adds roughly a third. So 15 MB of raw files already accounts for most of the budget, and the body competes for the same space. A batch send is held to the same 20 MB per message, and the whole request body is capped at 20 MB as well.
5498
6035
  *
5499
6036
  */
5500
6037
  attachments?: Array<EmailAttachment>;
5501
6038
  /**
5502
- * Schedule the message to send at a future time instead of immediately. Must be at least 30 seconds and at most 30 days ahead outside that range the request is rejected with `422`. The message returns with status `accepted` and shows as `scheduled` on reads until it sends; cancel it before then with the message cancel endpoint. Scheduled sends count against your plan's monthly scheduled-email allowance; exceeding it is rejected with a `422`.
6039
+ * Schedule the message to send at a future time instead of immediately. Must be at least 30 seconds and at most 30 days ahead. Outside that range the request is rejected with `422`. The message returns with status `accepted` and shows as `scheduled` on reads until it sends. Cancel it before then with the message cancel endpoint. Scheduled sends count against your plan's monthly scheduled-email allowance. Exceeding it is rejected with a `422`. A scheduled message has inline content: `scheduled_at` and `template` are mutually exclusive, and combining them is rejected with a `422`. This field is only accepted on a single send, not on a batch item.
5503
6040
  *
5504
6041
  */
5505
6042
  scheduled_at?: string;
5506
- /**
5507
- * Preview feature — contact-targeted sends. Currently unavailable; supplying this field returns `422 UnsupportedEmailFeature`.
5508
- */
5509
- contact_id?: string;
5510
- /**
5511
- * Preview feature — topic-gated sends. Currently unavailable; supplying this field returns `422 UnsupportedEmailFeature`. 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`.
5512
- *
5513
- */
5514
- topic_id?: string;
5515
6043
  };
5516
6044
  type EmailAttachmentId = string;
5517
6045
  /**
5518
- * Attachment metadata returned on API reads. The original content is not echoed back inline only the metadata needed for display and audit. To download the raw attachment bytes (while content storage is enabled and within the retention window), use `GET /v1/email/messages/{message_id}/attachments/{attachment_id}`, which returns the file with its own content type and a Content-Disposition filename.
6046
+ * Attachment metadata returned on API reads. The original content is not sent back inline, only the metadata you need to display and audit it. To download the raw attachment bytes (while content storage is enabled and within the retention window), use `GET /v1/email/messages/{message_id}/attachments/{attachment_id}`, which returns the file with its own content type and a Content-Disposition filename.
5519
6047
  *
5520
6048
  */
5521
6049
  type EmailAttachmentRef = {
@@ -5548,19 +6076,20 @@ type EmailAttachmentRef = {
5548
6076
  /**
5549
6077
  * Aggregate delivery status of an email, derived from its recipients' states.
5550
6078
  *
5551
- * In flight: `scheduled` means the message is queued to send at a future time and has
5552
- * not been dispatched yet; `accepted` (the initial status of an immediate send) means
5553
- * Bird has queued the message for its recipients; `processed` means delivery is underway
5554
- * (at least one recipient has been handed to the delivery pipeline and none has failed);
5555
- * `deferred` means at least one recipient's mailbox provider asked Bird to retry and
5556
- * delivery attempts continue.
6079
+ * In flight:
6080
+ *
6081
+ * - `scheduled`: The message is queued to send at a future time and has not been dispatched yet.
6082
+ * - `accepted`: The initial status of an immediate send. The message is queued for its recipients.
6083
+ * - `processed`: Delivery is underway, so at least one recipient's message is on its way out and none has failed.
6084
+ * - `deferred`: At least one recipient's mailbox provider asked for a retry, and delivery attempts continue.
5557
6085
  *
5558
- * Final: `delivered` means every recipient's mail server accepted the message; `bounced`
5559
- * means every recipient permanently failed (bounced or was rejected); `rejected` means
5560
- * every recipient was rejected before a delivery attempt (for example, all recipients
5561
- * suppressed); `partial_failure` means some recipients permanently failed while others
5562
- * were delivered or are still in flight; `canceled` means a scheduled message was
5563
- * canceled before it was sent.
6086
+ * Final:
6087
+ *
6088
+ * - `delivered`: Every recipient's mail server accepted the message.
6089
+ * - `bounced`: Every recipient permanently failed (bounced or was rejected).
6090
+ * - `rejected`: Every recipient was rejected before a delivery attempt (for example, all recipients were suppressed).
6091
+ * - `partial_failure`: Some recipients permanently failed while others were delivered or are still in flight.
6092
+ * - `canceled`: A scheduled message was canceled before it was sent.
5564
6093
  *
5565
6094
  * `complained` takes precedence over every other status: at least one recipient reported
5566
6095
  * the message as spam, regardless of what happened to the rest.
@@ -5577,7 +6106,7 @@ type EmailMessage = {
5577
6106
  */
5578
6107
  from: EmailAddress;
5579
6108
  /**
5580
- * 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.
6109
+ * 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.
5581
6110
  */
5582
6111
  to: Array<EmailAddress>;
5583
6112
  /**
@@ -5598,21 +6127,17 @@ type EmailMessage = {
5598
6127
  * Reply-To addresses, if set on the send. Empty/null when no Reply-To was provided.
5599
6128
  */
5600
6129
  reply_to?: Array<EmailAddress> | null;
5601
- /**
5602
- * Aggregate delivery status derived from recipient states. `scheduled` means the message is queued to send at a future time and has not been dispatched yet. `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. `canceled` means a scheduled message was canceled before it was sent.
5603
- *
5604
- */
5605
6130
  readonly status: EmailMessageStatus;
5606
6131
  /**
5607
- * Number of recipients currently in the `accepted` state Bird has the send and is preparing to deliver.
6132
+ * How many recipients are in the `accepted` state, meaning we have the message and are getting ready to deliver it.
5608
6133
  */
5609
6134
  readonly accepted_count: number;
5610
6135
  /**
5611
- * Number of recipients for whom Bird has processed the message and queued it for delivery.
6136
+ * How many recipients the message has been prepared for and queued for delivery.
5612
6137
  */
5613
6138
  readonly processed_count: number;
5614
6139
  /**
5615
- * Number of recipients whose messages were accepted by the remote MTA.
6140
+ * How many recipients' messages were accepted by their mail server.
5616
6141
  */
5617
6142
  readonly delivered_count: number;
5618
6143
  /**
@@ -5624,16 +6149,16 @@ type EmailMessage = {
5624
6149
  */
5625
6150
  readonly complained_count: number;
5626
6151
  /**
5627
- * Number of recipients in transient delivery deferral; the provider is retrying.
6152
+ * Number of recipients in transient delivery deferral. Their mail server asked for a retry, and delivery attempts continue.
5628
6153
  */
5629
6154
  readonly deferred_count: number;
5630
6155
  /**
5631
- * Number of recipients rejected before delivery. See the per-recipient `rejection_reason` field on `GET /v1/email/messages/{message_id}/recipients` for the specific cause (suppression match, transmission failure, generation failure, or policy refusal).
6156
+ * Number of recipients rejected before delivery. Read the per-recipient `rejection_reason` field on `GET /v1/email/messages/{message_id}/recipients` for the specific cause.
5632
6157
  *
5633
6158
  */
5634
6159
  readonly rejected_count: number;
5635
6160
  /**
5636
- * 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`.
6161
+ * Time between the send being accepted and the message being prepared for delivery, in milliseconds, for the fastest recipient. Null until the first recipient reaches `processed`.
5637
6162
  *
5638
6163
  */
5639
6164
  readonly processing_latency_ms?: number | null;
@@ -5676,11 +6201,11 @@ type EmailMessage = {
5676
6201
  */
5677
6202
  readonly template_version_id?: EmailTemplateVersionId | null;
5678
6203
  /**
5679
- * Structured `{name, value}` filter labels applied to this send. See EmailMessageSendRequest for the tags vs metadata distinction.
6204
+ * Labels on this message, each one a `name` and a `value`, that you can filter and search messages by. Use tags for anything you want to find messages by later, and `metadata` for data you only want handed back to you.
5680
6205
  */
5681
6206
  tags?: Array<Tag>;
5682
6207
  /**
5683
- * Arbitrary JSON metadata stored on the message object and echoed in webhook payloads. See EmailMessageSendRequest for the tags vs metadata distinction.
6208
+ * Any JSON you kept on the message. We store it and hand it back in webhook payloads, and that is all it does. If you want to search or filter by it, use `tags` instead.
5684
6209
  */
5685
6210
  metadata?: {
5686
6211
  [key: string]: unknown;
@@ -5693,7 +6218,7 @@ type EmailMessage = {
5693
6218
  [key: string]: unknown;
5694
6219
  } | null;
5695
6220
  /**
5696
- * Attachment metadata for the send. Empty when no attachments were included. Raw content is not echoed; when content storage is enabled, download an attachment by its `id` via the message's attachment endpoint.
6221
+ * Attachment metadata for the send. Empty when no attachments were included. Raw content is not echoed. When content storage is enabled, download an attachment by its `id` via the message's attachment endpoint.
5697
6222
  */
5698
6223
  attachments?: Array<EmailAttachmentRef>;
5699
6224
  /**
@@ -5709,7 +6234,7 @@ type EmailMessage = {
5709
6234
  */
5710
6235
  readonly created_at: string;
5711
6236
  /**
5712
- * Thread this message belongs to. Null until threading is enabled.
6237
+ * Thread this message belongs to, or null when the message is not part of one.
5713
6238
  */
5714
6239
  readonly thread_id?: string | null;
5715
6240
  /**
@@ -5871,15 +6396,16 @@ type PublishRealtimeAppEventData = {
5871
6396
  */
5872
6397
  "X-Workspace-Id"?: string;
5873
6398
  /**
5874
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6399
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6400
+ *
5875
6401
  * Two distinct 409 errors signal misuse:
5876
- * - `request_in_progress` (E01004): the same key is currently being
5877
- * processed by a concurrent request. Wait briefly and retry; the lock
5878
- * expires within 30 seconds.
5879
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6402
+ *
6403
+ * - `request_in_progress` (E01004): The same key is currently being
6404
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6405
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
5880
6406
  * against a different request body or method. Generate a new key.
5881
6407
  *
5882
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6408
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
5883
6409
  *
5884
6410
  */
5885
6411
  "Idempotency-Key"?: string;
@@ -5901,15 +6427,16 @@ type PublishRealtimeAppBatchData = {
5901
6427
  */
5902
6428
  "X-Workspace-Id"?: string;
5903
6429
  /**
5904
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6430
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6431
+ *
5905
6432
  * Two distinct 409 errors signal misuse:
5906
- * - `request_in_progress` (E01004): the same key is currently being
5907
- * processed by a concurrent request. Wait briefly and retry; the lock
5908
- * expires within 30 seconds.
5909
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6433
+ *
6434
+ * - `request_in_progress` (E01004): The same key is currently being
6435
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6436
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
5910
6437
  * against a different request body or method. Generate a new key.
5911
6438
  *
5912
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6439
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
5913
6440
  *
5914
6441
  */
5915
6442
  "Idempotency-Key"?: string;
@@ -5983,15 +6510,16 @@ type SendRealtimeAppMemberEventData = {
5983
6510
  */
5984
6511
  "X-Workspace-Id"?: string;
5985
6512
  /**
5986
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6513
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6514
+ *
5987
6515
  * Two distinct 409 errors signal misuse:
5988
- * - `request_in_progress` (E01004): the same key is currently being
5989
- * processed by a concurrent request. Wait briefly and retry; the lock
5990
- * expires within 30 seconds.
5991
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6516
+ *
6517
+ * - `request_in_progress` (E01004): The same key is currently being
6518
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6519
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
5992
6520
  * against a different request body or method. Generate a new key.
5993
6521
  *
5994
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6522
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
5995
6523
  *
5996
6524
  */
5997
6525
  "Idempotency-Key"?: string;
@@ -6038,7 +6566,7 @@ type ListEmailMessagesData = {
6038
6566
  */
6039
6567
  status?: EmailMessageStatus;
6040
6568
  /**
6041
- * Filter by tag. Accepts `name` to match any message carrying that tag name, or `name:value` to match a specific tag pair (e.g. `category:welcome`). Repeat the parameter to AND-combine several tag filters.
6569
+ * Filter by tag. Accepts `name` to match any message carrying that tag name, or `name:value` to match a specific tag pair (for example `category:welcome`). Repeat the parameter to add more tags. A message must match every tag listed to be returned.
6042
6570
  *
6043
6571
  */
6044
6572
  tag?: Array<string>;
@@ -6047,12 +6575,12 @@ type ListEmailMessagesData = {
6047
6575
  */
6048
6576
  category?: EmailMessageCategory;
6049
6577
  /**
6050
- * Filter by recipient address. Exact match against any `to`/`cc`/`bcc` recipient on the message; normalised to lowercase before comparison.
6578
+ * Filter by recipient address. Exact match against any `to`/`cc`/`bcc` recipient on the message. The address is normalized to lowercase before comparison.
6051
6579
  *
6052
6580
  */
6053
6581
  to?: string;
6054
6582
  /**
6055
- * Filter by sender address. Exact match against the message `from` field; normalised to lowercase before comparison.
6583
+ * Filter by sender address. Exact match against the message `from` field. The address is normalized to lowercase before comparison.
6056
6584
  *
6057
6585
  */
6058
6586
  from?: string;
@@ -6068,9 +6596,9 @@ type ListContactsData = {
6068
6596
  */
6069
6597
  email?: string;
6070
6598
  /**
6071
- * Return the contact with exactly this phone number in international E.164 form. Encode the leading plus sign as `%2B` (an unencoded `+` arrives as a space and is rejected). Phone numbers are unique within a workspace, so this matches at most one contact. Non-canonical forms of the same number match the contact they canonicalize to; a value that is not a phone number shape, or an empty value, is a validation error, never an unfiltered page.
6599
+ * Return the contacts with exactly this phone number in international E.164 form. Repeat the parameter to match any of up to 50 numbers, and set `limit` to at least the number of values you pass: `limit` defaults to 25, and a page cut short by it looks exactly like numbers that matched nothing. Different identifier parameters still combine with AND, so `phone_number=a&phone_number=b&email=c` asks for a contact whose phone number is `a` or `b` and whose email is `c`. Encode the leading plus sign as `%2B` (an unencoded `+` arrives as a space and is rejected). Phone numbers are unique within a workspace, so each value matches at most one contact. Non-canonical forms of the same number match the contact they canonicalize to; a value that is not a phone number shape, or an empty value, is a validation error, never an unfiltered page.
6072
6600
  */
6073
- phone_number?: string;
6601
+ phone_number?: Array<string>;
6074
6602
  /**
6075
6603
  * Return the contact with exactly this external_id (your own identifier for the contact). Unique within a workspace, so this matches at most one contact. An empty value is a validation error, never an unfiltered page.
6076
6604
  */
@@ -6106,15 +6634,16 @@ type CreateContactData = {
6106
6634
  body: ContactCreateRequest;
6107
6635
  headers?: {
6108
6636
  /**
6109
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6637
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6638
+ *
6110
6639
  * Two distinct 409 errors signal misuse:
6111
- * - `request_in_progress` (E01004): the same key is currently being
6112
- * processed by a concurrent request. Wait briefly and retry; the lock
6113
- * expires within 30 seconds.
6114
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6640
+ *
6641
+ * - `request_in_progress` (E01004): The same key is currently being
6642
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6643
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6115
6644
  * against a different request body or method. Generate a new key.
6116
6645
  *
6117
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6646
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6118
6647
  *
6119
6648
  */
6120
6649
  "Idempotency-Key"?: string;
@@ -6127,15 +6656,16 @@ type CreateContactBatchData = {
6127
6656
  body: ContactUpsertRequest;
6128
6657
  headers?: {
6129
6658
  /**
6130
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6659
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6660
+ *
6131
6661
  * Two distinct 409 errors signal misuse:
6132
- * - `request_in_progress` (E01004): the same key is currently being
6133
- * processed by a concurrent request. Wait briefly and retry; the lock
6134
- * expires within 30 seconds.
6135
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6662
+ *
6663
+ * - `request_in_progress` (E01004): The same key is currently being
6664
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6665
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6136
6666
  * against a different request body or method. Generate a new key.
6137
6667
  *
6138
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6668
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6139
6669
  *
6140
6670
  */
6141
6671
  "Idempotency-Key"?: string;
@@ -6148,15 +6678,16 @@ type UpdateContactData = {
6148
6678
  body: ContactUpdateRequest;
6149
6679
  headers?: {
6150
6680
  /**
6151
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6681
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6682
+ *
6152
6683
  * Two distinct 409 errors signal misuse:
6153
- * - `request_in_progress` (E01004): the same key is currently being
6154
- * processed by a concurrent request. Wait briefly and retry; the lock
6155
- * expires within 30 seconds.
6156
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6684
+ *
6685
+ * - `request_in_progress` (E01004): The same key is currently being
6686
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6687
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6157
6688
  * against a different request body or method. Generate a new key.
6158
6689
  *
6159
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6690
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6160
6691
  *
6161
6692
  */
6162
6693
  "Idempotency-Key"?: string;
@@ -6193,15 +6724,16 @@ type CreateContactPropertyData = {
6193
6724
  body: ContactPropertyCreateRequest;
6194
6725
  headers?: {
6195
6726
  /**
6196
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6727
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6728
+ *
6197
6729
  * Two distinct 409 errors signal misuse:
6198
- * - `request_in_progress` (E01004): the same key is currently being
6199
- * processed by a concurrent request. Wait briefly and retry; the lock
6200
- * expires within 30 seconds.
6201
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6730
+ *
6731
+ * - `request_in_progress` (E01004): The same key is currently being
6732
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6733
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6202
6734
  * against a different request body or method. Generate a new key.
6203
6735
  *
6204
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6736
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6205
6737
  *
6206
6738
  */
6207
6739
  "Idempotency-Key"?: string;
@@ -6214,15 +6746,16 @@ type UpdateContactPropertyData = {
6214
6746
  body: ContactPropertyUpdateRequest;
6215
6747
  headers?: {
6216
6748
  /**
6217
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6749
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6750
+ *
6218
6751
  * Two distinct 409 errors signal misuse:
6219
- * - `request_in_progress` (E01004): the same key is currently being
6220
- * processed by a concurrent request. Wait briefly and retry; the lock
6221
- * expires within 30 seconds.
6222
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6752
+ *
6753
+ * - `request_in_progress` (E01004): The same key is currently being
6754
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6755
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6223
6756
  * against a different request body or method. Generate a new key.
6224
6757
  *
6225
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6758
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6226
6759
  *
6227
6760
  */
6228
6761
  "Idempotency-Key"?: string;
@@ -6263,15 +6796,16 @@ type CreateAudienceData = {
6263
6796
  body: AudienceCreateRequest;
6264
6797
  headers?: {
6265
6798
  /**
6266
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6799
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6800
+ *
6267
6801
  * Two distinct 409 errors signal misuse:
6268
- * - `request_in_progress` (E01004): the same key is currently being
6269
- * processed by a concurrent request. Wait briefly and retry; the lock
6270
- * expires within 30 seconds.
6271
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6802
+ *
6803
+ * - `request_in_progress` (E01004): The same key is currently being
6804
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6805
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6272
6806
  * against a different request body or method. Generate a new key.
6273
6807
  *
6274
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6808
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6275
6809
  *
6276
6810
  */
6277
6811
  "Idempotency-Key"?: string;
@@ -6284,15 +6818,16 @@ type UpdateAudienceData = {
6284
6818
  body: AudienceUpdateRequest;
6285
6819
  headers?: {
6286
6820
  /**
6287
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6821
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6822
+ *
6288
6823
  * Two distinct 409 errors signal misuse:
6289
- * - `request_in_progress` (E01004): the same key is currently being
6290
- * processed by a concurrent request. Wait briefly and retry; the lock
6291
- * expires within 30 seconds.
6292
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6824
+ *
6825
+ * - `request_in_progress` (E01004): The same key is currently being
6826
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6827
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6293
6828
  * against a different request body or method. Generate a new key.
6294
6829
  *
6295
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6830
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6296
6831
  *
6297
6832
  */
6298
6833
  "Idempotency-Key"?: string;
@@ -6338,15 +6873,16 @@ type AssignAudienceContactsData = {
6338
6873
  body: AudienceContactsAddRequest;
6339
6874
  headers?: {
6340
6875
  /**
6341
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6876
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6877
+ *
6342
6878
  * Two distinct 409 errors signal misuse:
6343
- * - `request_in_progress` (E01004): the same key is currently being
6344
- * processed by a concurrent request. Wait briefly and retry; the lock
6345
- * expires within 30 seconds.
6346
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6879
+ *
6880
+ * - `request_in_progress` (E01004): The same key is currently being
6881
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6882
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6347
6883
  * against a different request body or method. Generate a new key.
6348
6884
  *
6349
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6885
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6350
6886
  *
6351
6887
  */
6352
6888
  "Idempotency-Key"?: string;
@@ -6364,15 +6900,16 @@ type UnassignAudienceContactsData = {
6364
6900
  body: AudienceContactsRemoveRequest;
6365
6901
  headers?: {
6366
6902
  /**
6367
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
6903
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
6904
+ *
6368
6905
  * Two distinct 409 errors signal misuse:
6369
- * - `request_in_progress` (E01004): the same key is currently being
6370
- * processed by a concurrent request. Wait briefly and retry; the lock
6371
- * expires within 30 seconds.
6372
- * - `idempotency_key_reuse` (E01005): the same key has already completed
6906
+ *
6907
+ * - `request_in_progress` (E01004): The same key is currently being
6908
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
6909
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6373
6910
  * against a different request body or method. Generate a new key.
6374
6911
  *
6375
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
6912
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6376
6913
  *
6377
6914
  */
6378
6915
  "Idempotency-Key"?: string;
@@ -6437,7 +6974,7 @@ type ListSmsMessagesData = {
6437
6974
  */
6438
6975
  from?: string;
6439
6976
  /**
6440
- * Filter by tag. Accepts `name` to match any message carrying that tag name, or `name:value` to match a specific tag pair (e.g. `category:welcome`). Repeat the parameter to AND-combine several tag filters.
6977
+ * Filter by tag. Accepts `name` to match any message carrying that tag name, or `name:value` to match a specific tag pair (for example `category:welcome`). Repeat the parameter to add more tags. A message must match every tag listed to be returned.
6441
6978
  *
6442
6979
  */
6443
6980
  tag?: Array<string>;
@@ -6449,7 +6986,7 @@ type ListSmsTemplatesData = {
6449
6986
  path?: never;
6450
6987
  query?: {
6451
6988
  /**
6452
- * Keep only templates of this scope: `system` for Bird's built-in templates, `workspace` for templates authored in your workspace. Omit for all. Workspace-authored SMS templates are not available yet, so `workspace` currently matches nothing.
6989
+ * Keep only templates of this scope: `system` for Bird's built-in templates, `workspace` for templates authored in your workspace. Omit for all.
6453
6990
  *
6454
6991
  */
6455
6992
  scope?: TemplateScope;
@@ -6461,10 +6998,62 @@ type ListSmsTemplatesData = {
6461
6998
  * Keep only templates available in this language, as a BCP-47 tag. Matches the template's `available_languages` entries exactly, with no fallback.
6462
6999
  *
6463
7000
  */
6464
- language?: string;
7001
+ language?: LanguageTag;
6465
7002
  };
6466
7003
  url: "/v1/sms/templates";
6467
7004
  };
7005
+ type CreatePhoneNumberLookupData = {
7006
+ body: PhoneNumberLookupRequest;
7007
+ headers?: {
7008
+ /**
7009
+ * Workspace context. Required for session auth; derived from API key otherwise.
7010
+ */
7011
+ "X-Workspace-Id"?: string;
7012
+ /**
7013
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
7014
+ *
7015
+ * Two distinct 409 errors signal misuse:
7016
+ *
7017
+ * - `request_in_progress` (E01004): The same key is currently being
7018
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
7019
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
7020
+ * against a different request body or method. Generate a new key.
7021
+ *
7022
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
7023
+ *
7024
+ */
7025
+ "Idempotency-Key"?: string;
7026
+ };
7027
+ path?: never;
7028
+ query?: never;
7029
+ url: "/v1/lookup/phone-number";
7030
+ };
7031
+ type CreateEmailLookupData = {
7032
+ body: EmailLookupRequest;
7033
+ headers?: {
7034
+ /**
7035
+ * Workspace context. Required for session auth; derived from API key otherwise.
7036
+ */
7037
+ "X-Workspace-Id"?: string;
7038
+ /**
7039
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
7040
+ *
7041
+ * Two distinct 409 errors signal misuse:
7042
+ *
7043
+ * - `request_in_progress` (E01004): The same key is currently being
7044
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
7045
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
7046
+ * against a different request body or method. Generate a new key.
7047
+ *
7048
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
7049
+ *
7050
+ */
7051
+ "Idempotency-Key"?: string;
7052
+ };
7053
+ path?: never;
7054
+ query?: never;
7055
+ url: "/v1/lookup/email";
7056
+ };
6468
7057
  type CreateVerificationData = {
6469
7058
  body: VerificationCreateRequest;
6470
7059
  headers?: {
@@ -6473,15 +7062,16 @@ type CreateVerificationData = {
6473
7062
  */
6474
7063
  "X-Workspace-Id"?: string;
6475
7064
  /**
6476
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
7065
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
7066
+ *
6477
7067
  * Two distinct 409 errors signal misuse:
6478
- * - `request_in_progress` (E01004): the same key is currently being
6479
- * processed by a concurrent request. Wait briefly and retry; the lock
6480
- * expires within 30 seconds.
6481
- * - `idempotency_key_reuse` (E01005): the same key has already completed
7068
+ *
7069
+ * - `request_in_progress` (E01004): The same key is currently being
7070
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
7071
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6482
7072
  * against a different request body or method. Generate a new key.
6483
7073
  *
6484
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
7074
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6485
7075
  *
6486
7076
  */
6487
7077
  "Idempotency-Key"?: string;
@@ -6498,15 +7088,16 @@ type CreateVerificationCheckData = {
6498
7088
  */
6499
7089
  "X-Workspace-Id"?: string;
6500
7090
  /**
6501
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
7091
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
7092
+ *
6502
7093
  * Two distinct 409 errors signal misuse:
6503
- * - `request_in_progress` (E01004): the same key is currently being
6504
- * processed by a concurrent request. Wait briefly and retry; the lock
6505
- * expires within 30 seconds.
6506
- * - `idempotency_key_reuse` (E01005): the same key has already completed
7094
+ *
7095
+ * - `request_in_progress` (E01004): The same key is currently being
7096
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
7097
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6507
7098
  * against a different request body or method. Generate a new key.
6508
7099
  *
6509
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
7100
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6510
7101
  *
6511
7102
  */
6512
7103
  "Idempotency-Key"?: string;
@@ -6523,15 +7114,16 @@ type CreateVerificationNextChannelData = {
6523
7114
  */
6524
7115
  "X-Workspace-Id"?: string;
6525
7116
  /**
6526
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
7117
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
7118
+ *
6527
7119
  * Two distinct 409 errors signal misuse:
6528
- * - `request_in_progress` (E01004): the same key is currently being
6529
- * processed by a concurrent request. Wait briefly and retry; the lock
6530
- * expires within 30 seconds.
6531
- * - `idempotency_key_reuse` (E01005): the same key has already completed
7120
+ *
7121
+ * - `request_in_progress` (E01004): The same key is currently being
7122
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
7123
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
6532
7124
  * against a different request body or method. Generate a new key.
6533
7125
  *
6534
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
7126
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
6535
7127
  *
6536
7128
  */
6537
7129
  "Idempotency-Key"?: string;
@@ -6586,7 +7178,7 @@ type ListWhatsAppMessagesData = {
6586
7178
  */
6587
7179
  category?: WhatsAppTemplateCategory$1;
6588
7180
  /**
6589
- * Filter by tag. Accepts `name` to match any message carrying that tag name, or `name:value` to match a specific tag pair (e.g. `category:welcome`). Repeat the parameter to AND-combine several tag filters.
7181
+ * Filter by tag. Accepts `name` to match any message carrying that tag name, or `name:value` to match a specific tag pair (for example `category:welcome`). Repeat the parameter to add more tags. A message must match every tag listed to be returned.
6590
7182
  *
6591
7183
  */
6592
7184
  tag?: Array<string>;
@@ -6606,7 +7198,7 @@ type ListWhatsAppMessageEventsData = {
6606
7198
  * Keep only events of this exact type (for example `whatsapp.delivered` or `whatsapp.failed`). Omit for the full timeline.
6607
7199
  *
6608
7200
  */
6609
- type?: string;
7201
+ type?: WhatsAppEventType$1;
6610
7202
  };
6611
7203
  url: "/v1/whatsapp/messages/{message_id}/events";
6612
7204
  };
@@ -6713,7 +7305,7 @@ type GetEmailStatsByTagData = {
6713
7305
  path?: never;
6714
7306
  query?: {
6715
7307
  /**
6716
- * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). Defaults to 30 days before `to` when omitted; with `include_trend=true` and `trend_grain=hourly` the default tightens to 29 days before `to`, keeping the defaulted window within the 720-hour trend cap.
7308
+ * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). It defaults to 30 days before `to` when you leave it out. When `include_trend=true` and `trend_grain=hourly`, that default tightens to 29 days before `to` instead, so the defaulted window still fits inside the 720-hour trend cap.
6717
7309
  */
6718
7310
  from?: string;
6719
7311
  /**
@@ -6726,11 +7318,11 @@ type GetEmailStatsByTagData = {
6726
7318
  */
6727
7319
  timezone?: string;
6728
7320
  /**
6729
- * Not supported on breakdown endpoints; supplying it returns 422. To compare categories use `GET /v1/email/stats/categories`; the summary, daily, and hourly statistics accept `category` as a filter.
7321
+ * Not supported on breakdown endpoints. Supplying it returns 422. To compare categories, use `GET /v1/email/stats/categories`. The summary, daily, and hourly statistics accept `category` as a filter.
6730
7322
  */
6731
7323
  category?: string;
6732
7324
  /**
6733
- * Metric to rank rows by, applied descending. Any count or rate in the response may be used; rows whose rate is undefined (zero denominator) sort last. Defaults to `processed`.
7325
+ * Metric to rank rows by, applied descending. Any count or rate in the response can be used. A row whose rate is undefined because its denominator is zero sorts last. It defaults to `processed`.
6734
7326
  *
6735
7327
  */
6736
7328
  sort?: EmailStatsSortMetric;
@@ -6739,7 +7331,7 @@ type GetEmailStatsByTagData = {
6739
7331
  */
6740
7332
  limit?: number;
6741
7333
  /**
6742
- * When true, each row also carries a `trend` array: a short per-bucket series of that row's delivery and engagement rates over the window. Returned only when `limit` is 50 or fewer and the window is at most 90 days (trend_grain=daily) or 720 hours (trend_grain=hourly); a larger request returns 422. When `from` is omitted and `trend_grain=hourly`, the default window is 30 days (720 hours), so a request built entirely from defaults always fits the cap.
7334
+ * When true, each row also gets a `trend` array: a short per-bucket series showing that tag's delivery and engagement rates over the window. This only works when `limit` is 50 or fewer and the window is at most 90 days for `trend_grain=daily` or 720 hours for `trend_grain=hourly`. Ask for more and you get a 422. When you leave `from` out and use `trend_grain=hourly`, the default window tightens to 29 days before `to` (720 hours total), so a request built entirely from defaults always fits inside the cap.
6743
7335
  *
6744
7336
  */
6745
7337
  include_trend?: boolean;
@@ -6811,7 +7403,7 @@ type GetEmailStatsBySendingIpData = {
6811
7403
  path?: never;
6812
7404
  query?: {
6813
7405
  /**
6814
- * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). Defaults to 30 days before `to` when omitted; with `include_trend=true` and `trend_grain=hourly` the default tightens to 29 days before `to`, keeping the defaulted window within the 720-hour trend cap.
7406
+ * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). It defaults to 30 days before `to` when you leave it out. When `include_trend=true` and `trend_grain=hourly`, that default tightens to 29 days before `to` instead, so the defaulted window still fits inside the 720-hour trend cap.
6815
7407
  */
6816
7408
  from?: string;
6817
7409
  /**
@@ -6824,11 +7416,11 @@ type GetEmailStatsBySendingIpData = {
6824
7416
  */
6825
7417
  timezone?: string;
6826
7418
  /**
6827
- * Not supported on breakdown endpoints; supplying it returns 422. To compare categories use `GET /v1/email/stats/categories`; the summary, daily, and hourly statistics accept `category` as a filter.
7419
+ * Not supported on breakdown endpoints. Supplying it returns 422. To compare categories, use `GET /v1/email/stats/categories`. The summary, daily, and hourly statistics accept `category` as a filter.
6828
7420
  */
6829
7421
  category?: string;
6830
7422
  /**
6831
- * Metric to rank IPs by, applied descending. `bounces.block` surfaces the IPs whose reputation is most likely degraded. Rows whose rate is undefined (zero denominator) sort last. Defaults to `delivered`. Engagement metrics (a sending IP carries no engagement), `processed`, `rejected`, and `oob_bounces` are not sortable here.
7423
+ * Metric to rank IPs by, applied descending. Sorting by `bounces.block` puts the IPs whose reputation is most likely degraded at the top. A row whose rate is undefined because its denominator is zero sorts last. It defaults to `delivered`. A sending IP has no engagement, so engagement metrics aren't sortable here, and neither are `processed`, `rejected`, or `oob_bounces`.
6832
7424
  *
6833
7425
  */
6834
7426
  sort?: "delivered" | "bounced" | "complained" | "deferred" | "bounces.hard" | "bounces.soft" | "bounces.admin" | "bounces.block" | "bounces.undetermined" | "delivery_rate" | "bounce_rate" | "complaint_rate" | "bounces.hard_rate" | "bounces.soft_rate" | "bounces.admin_rate" | "bounces.block_rate" | "bounces.undetermined_rate";
@@ -6837,7 +7429,7 @@ type GetEmailStatsBySendingIpData = {
6837
7429
  */
6838
7430
  limit?: number;
6839
7431
  /**
6840
- * When true, each row also carries a `trend` array: a short per-bucket series of that IP's delivery rates over the window (per-IP rows have no engagement, so each trend point's open and click rates read 0 in buckets that had deliveries and null in buckets that had none). Returned only when `limit` is 50 or fewer and the window is at most 90 days (trend_grain=daily) or 720 hours (trend_grain=hourly); a larger request returns 422. When `from` is omitted and `trend_grain=hourly`, the default window is 30 days (720 hours), so a request built entirely from defaults always fits the cap.
7432
+ * When true, each row also gets a `trend` array: a short per-bucket series showing that IP's delivery rates over the window. A trend point's open and click rates read `0` in a bucket that had deliveries and `null` in one that had none, because a sending IP has no engagement data. This only works when `limit` is 50 or fewer and the window is at most 90 days for `trend_grain=daily` or 720 hours for `trend_grain=hourly`. Ask for more and you get a 422. When you leave `from` out and use `trend_grain=hourly`, the default window tightens to 29 days before `to` (720 hours total), so a request built entirely from defaults always fits inside the cap.
6841
7433
  *
6842
7434
  */
6843
7435
  include_trend?: boolean;
@@ -6853,7 +7445,7 @@ type GetEmailStatsBySendingDomainData = {
6853
7445
  path?: never;
6854
7446
  query?: {
6855
7447
  /**
6856
- * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). Defaults to 30 days before `to` when omitted; with `include_trend=true` and `trend_grain=hourly` the default tightens to 29 days before `to`, keeping the defaulted window within the 720-hour trend cap.
7448
+ * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). It defaults to 30 days before `to` when you leave it out. When `include_trend=true` and `trend_grain=hourly`, that default tightens to 29 days before `to` instead, so the defaulted window still fits inside the 720-hour trend cap.
6857
7449
  */
6858
7450
  from?: string;
6859
7451
  /**
@@ -6866,11 +7458,11 @@ type GetEmailStatsBySendingDomainData = {
6866
7458
  */
6867
7459
  timezone?: string;
6868
7460
  /**
6869
- * Not supported on breakdown endpoints; supplying it returns 422. To compare categories use `GET /v1/email/stats/categories`; the summary, daily, and hourly statistics accept `category` as a filter.
7461
+ * Not supported on breakdown endpoints. Supplying it returns 422. To compare categories, use `GET /v1/email/stats/categories`. The summary, daily, and hourly statistics accept `category` as a filter.
6870
7462
  */
6871
7463
  category?: string;
6872
7464
  /**
6873
- * Metric to rank rows by, applied descending. Any count or rate in the response may be used; rows whose rate is undefined (zero denominator) sort last. Defaults to `processed`.
7465
+ * Metric to rank rows by, applied descending. Any count or rate in the response can be used. A row whose rate is undefined because its denominator is zero sorts last. It defaults to `processed`.
6874
7466
  *
6875
7467
  */
6876
7468
  sort?: EmailStatsSortMetric;
@@ -6879,7 +7471,7 @@ type GetEmailStatsBySendingDomainData = {
6879
7471
  */
6880
7472
  limit?: number;
6881
7473
  /**
6882
- * When true, each row also carries a `trend` array: a short per-bucket series of that row's delivery and engagement rates over the window. Returned only when `limit` is 50 or fewer and the window is at most 90 days (trend_grain=daily) or 720 hours (trend_grain=hourly); a larger request returns 422. When `from` is omitted and `trend_grain=hourly`, the default window is 30 days (720 hours), so a request built entirely from defaults always fits the cap.
7474
+ * When true, each row also gets a `trend` array: a short per-bucket series showing that domain's delivery and engagement rates over the window. This only works when `limit` is 50 or fewer and the window is at most 90 days for `trend_grain=daily` or 720 hours for `trend_grain=hourly`. Ask for more and you get a 422. When you leave `from` out and use `trend_grain=hourly`, the default window tightens to 29 days before `to` (720 hours total), so a request built entirely from defaults always fits inside the cap.
6883
7475
  *
6884
7476
  */
6885
7477
  include_trend?: boolean;
@@ -6895,7 +7487,7 @@ type GetEmailStatsByCategoryData = {
6895
7487
  path?: never;
6896
7488
  query?: {
6897
7489
  /**
6898
- * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). Defaults to 30 days before `to` when omitted; with `include_trend=true` and `trend_grain=hourly` the default tightens to 29 days before `to`, keeping the defaulted window within the 720-hour trend cap.
7490
+ * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). It defaults to 30 days before `to` when you leave it out. When `include_trend=true` and `trend_grain=hourly`, that default tightens to 29 days before `to` instead, so the defaulted window still fits inside the 720-hour trend cap.
6899
7491
  */
6900
7492
  from?: string;
6901
7493
  /**
@@ -6908,7 +7500,7 @@ type GetEmailStatsByCategoryData = {
6908
7500
  */
6909
7501
  timezone?: string;
6910
7502
  /**
6911
- * Metric to rank rows by, applied descending. Any count or rate in the response may be used; rows whose rate is undefined (zero denominator) sort last. Defaults to `processed`.
7503
+ * Metric to rank rows by, applied descending. Any count or rate in the response can be used. A row whose rate is undefined because its denominator is zero sorts last. It defaults to `processed`.
6912
7504
  *
6913
7505
  */
6914
7506
  sort?: EmailStatsSortMetric;
@@ -6917,7 +7509,7 @@ type GetEmailStatsByCategoryData = {
6917
7509
  */
6918
7510
  limit?: number;
6919
7511
  /**
6920
- * When true, each row also carries a `trend` array: a short per-bucket series of that category's delivery and engagement rates over the window. Returned only when `limit` is 50 or fewer and the window is at most 90 days (trend_grain=daily) or 720 hours (trend_grain=hourly); a larger request returns 422. When `from` is omitted and `trend_grain=hourly`, the default window is 30 days (720 hours), so a request built entirely from defaults always fits the cap.
7512
+ * When true, each row also gets a `trend` array: a short per-bucket series showing that category's delivery and engagement rates over the window. This only works when `limit` is 50 or fewer and the window is at most 90 days for `trend_grain=daily` or 720 hours for `trend_grain=hourly`. Ask for more and you get a 422. When you leave `from` out and use `trend_grain=hourly`, the default window tightens to 29 days before `to` (720 hours total), so a request built entirely from defaults always fits inside the cap.
6921
7513
  *
6922
7514
  */
6923
7515
  include_trend?: boolean;
@@ -6933,7 +7525,7 @@ type GetEmailStatsByMailboxProviderData = {
6933
7525
  path?: never;
6934
7526
  query?: {
6935
7527
  /**
6936
- * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). Defaults to 30 days before `to` when omitted; with `include_trend=true` and `trend_grain=hourly` the default tightens to 29 days before `to`, keeping the defaulted window within the 720-hour trend cap.
7528
+ * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). It defaults to 30 days before `to` when you leave it out. When `include_trend=true` and `trend_grain=hourly`, that default tightens to 29 days before `to` instead, so the defaulted window still fits inside the 720-hour trend cap.
6937
7529
  */
6938
7530
  from?: string;
6939
7531
  /**
@@ -6950,7 +7542,7 @@ type GetEmailStatsByMailboxProviderData = {
6950
7542
  */
6951
7543
  category?: string;
6952
7544
  /**
6953
- * Metric to rank rows by, applied descending. Any count or rate in the response may be used; rows whose rate is undefined (zero denominator) sort last. Defaults to `delivered`. `processed`, `rejected`, and `oob_bounces` are not part of this breakdown's rows, so they are not sortable here.
7545
+ * Metric to rank rows by, applied descending. Any count or rate in the response can be used. A row whose rate is undefined because its denominator is zero sorts last. It defaults to `delivered`. `processed`, `rejected`, and `oob_bounces` are not part of this breakdown's rows, so they are not sortable here.
6954
7546
  *
6955
7547
  */
6956
7548
  sort?: EmailMailboxProviderSortMetric;
@@ -6959,7 +7551,7 @@ type GetEmailStatsByMailboxProviderData = {
6959
7551
  */
6960
7552
  limit?: number;
6961
7553
  /**
6962
- * When true, each row also carries a `trend` array: a short per-bucket series of that provider's delivery and engagement rates over the window. Returned only when `limit` is 50 or fewer and the window is at most 90 days (trend_grain=daily) or 720 hours (trend_grain=hourly); a larger request returns 422. When `from` is omitted and `trend_grain=hourly`, the default window is 30 days (720 hours), so a request built entirely from defaults always fits the cap.
7554
+ * When true, each row also gets a `trend` array: a short per-bucket series showing that provider's delivery and engagement rates over the window. This only works when `limit` is 50 or fewer and the window is at most 90 days for `trend_grain=daily` or 720 hours for `trend_grain=hourly`. Ask for more and you get a 422. When you leave `from` out and use `trend_grain=hourly`, the default window tightens to 29 days before `to` (720 hours total), so a request built entirely from defaults always fits inside the cap.
6963
7555
  *
6964
7556
  */
6965
7557
  include_trend?: boolean;
@@ -6975,7 +7567,7 @@ type GetEmailStatsByMailboxProviderRegionData = {
6975
7567
  path?: never;
6976
7568
  query?: {
6977
7569
  /**
6978
- * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). Defaults to 30 days before `to` when omitted; with `include_trend=true` and `trend_grain=hourly` the default tightens to 29 days before `to`, keeping the defaulted window within the 720-hour trend cap.
7570
+ * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). It defaults to 30 days before `to` when you leave it out. When `include_trend=true` and `trend_grain=hourly`, that default tightens to 29 days before `to` instead, so the defaulted window still fits inside the 720-hour trend cap.
6979
7571
  */
6980
7572
  from?: string;
6981
7573
  /**
@@ -6988,11 +7580,11 @@ type GetEmailStatsByMailboxProviderRegionData = {
6988
7580
  */
6989
7581
  timezone?: string;
6990
7582
  /**
6991
- * Not supported on breakdown endpoints; supplying it returns 422. To compare categories use `GET /v1/email/stats/categories`; the summary, daily, and hourly statistics accept `category` as a filter.
7583
+ * Not supported on breakdown endpoints. Supplying it returns 422. To compare categories, use `GET /v1/email/stats/categories`. The summary, daily, and hourly statistics accept `category` as a filter.
6992
7584
  */
6993
7585
  category?: string;
6994
7586
  /**
6995
- * Metric to rank rows by, applied descending. Any count or rate in the response may be used; rows whose rate is undefined (zero denominator) sort last. Defaults to `delivered`. `processed`, `rejected`, and `oob_bounces` are not part of this breakdown's rows, so they are not sortable here.
7587
+ * Metric to rank rows by, applied descending. Any count or rate in the response can be used. A row whose rate is undefined because its denominator is zero sorts last. It defaults to `delivered`. `processed`, `rejected`, and `oob_bounces` are not part of this breakdown's rows, so they are not sortable here.
6996
7588
  *
6997
7589
  */
6998
7590
  sort?: EmailMailboxProviderSortMetric;
@@ -7001,7 +7593,7 @@ type GetEmailStatsByMailboxProviderRegionData = {
7001
7593
  */
7002
7594
  limit?: number;
7003
7595
  /**
7004
- * When true, each row also carries a `trend` array: a short per-bucket series of that provider region's delivery and engagement rates over the window. Returned only when `limit` is 50 or fewer and the window is at most 90 days (trend_grain=daily) or 720 hours (trend_grain=hourly); a larger request returns 422. When `from` is omitted and `trend_grain=hourly`, the default window is 30 days (720 hours), so a request built entirely from defaults always fits the cap.
7596
+ * When true, each row also gets a `trend` array: a short per-bucket series showing that provider region's delivery and engagement rates over the window. This only works when `limit` is 50 or fewer and the window is at most 90 days for `trend_grain=daily` or 720 hours for `trend_grain=hourly`. Ask for more and you get a 422. When you leave `from` out and use `trend_grain=hourly`, the default window tightens to 29 days before `to` (720 hours total), so a request built entirely from defaults always fits inside the cap.
7005
7597
  *
7006
7598
  */
7007
7599
  include_trend?: boolean;
@@ -7017,7 +7609,7 @@ type GetEmailStatsByRecipientDomainData = {
7017
7609
  path?: never;
7018
7610
  query?: {
7019
7611
  /**
7020
- * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). Defaults to 30 days before `to` when omitted; with `include_trend=true` and `trend_grain=hourly` the default tightens to 29 days before `to`, keeping the defaulted window within the 720-hour trend cap.
7612
+ * Start date (inclusive) in YYYY-MM-DD, interpreted as a calendar day in `timezone` (a UTC day when `timezone` is omitted). It defaults to 30 days before `to` when you leave it out. When `include_trend=true` and `trend_grain=hourly`, that default tightens to 29 days before `to` instead, so the defaulted window still fits inside the 720-hour trend cap.
7021
7613
  */
7022
7614
  from?: string;
7023
7615
  /**
@@ -7030,11 +7622,11 @@ type GetEmailStatsByRecipientDomainData = {
7030
7622
  */
7031
7623
  timezone?: string;
7032
7624
  /**
7033
- * Not supported on breakdown endpoints; supplying it returns 422. To compare categories use `GET /v1/email/stats/categories`; the summary, daily, and hourly statistics accept `category` as a filter.
7625
+ * Not supported on breakdown endpoints. Supplying it returns 422. To compare categories, use `GET /v1/email/stats/categories`. The summary, daily, and hourly statistics accept `category` as a filter.
7034
7626
  */
7035
7627
  category?: string;
7036
7628
  /**
7037
- * Metric to rank rows by, applied descending. Any count or rate in the response may be used; rows whose rate is undefined (zero denominator) sort last. Defaults to `processed`.
7629
+ * Metric to rank rows by, applied descending. Any count or rate in the response can be used. A row whose rate is undefined because its denominator is zero sorts last. It defaults to `processed`.
7038
7630
  *
7039
7631
  */
7040
7632
  sort?: EmailStatsSortMetric;
@@ -7043,7 +7635,7 @@ type GetEmailStatsByRecipientDomainData = {
7043
7635
  */
7044
7636
  limit?: number;
7045
7637
  /**
7046
- * When true, each row also carries a `trend` array: a short per-bucket series of that recipient domain's delivery and engagement rates over the window. Returned only when `limit` is 50 or fewer and the window is at most 90 days (trend_grain=daily) or 720 hours (trend_grain=hourly); a larger request returns 422. When `from` is omitted and `trend_grain=hourly`, the default window is 30 days (720 hours), so a request built entirely from defaults always fits the cap.
7638
+ * When true, each row also gets a `trend` array: a short per-bucket series showing that recipient domain's delivery and engagement rates over the window. This only works when `limit` is 50 or fewer and the window is at most 90 days for `trend_grain=daily` or 720 hours for `trend_grain=hourly`. Ask for more and you get a 422. When you leave `from` out and use `trend_grain=hourly`, the default window tightens to 29 days before `to` (720 hours total), so a request built entirely from defaults always fits inside the cap.
7047
7639
  *
7048
7640
  */
7049
7641
  include_trend?: boolean;
@@ -7085,7 +7677,7 @@ type GetEmailStatsByTemplateData = {
7085
7677
  */
7086
7678
  limit?: number;
7087
7679
  /**
7088
- * When true, each row also carries a `trend` array: a short per-bucket series of that template's delivery and engagement rates over the window. Returned only when `limit` is 50 or fewer and the window is at most 90 days (trend_grain=daily) or 720 hours (trend_grain=hourly); a larger request returns 422. When `from` is omitted and `trend_grain=hourly`, the default window is 30 days (720 hours), so a request built entirely from defaults always fits the cap.
7680
+ * When true, each row also has a `trend` array: a short per-bucket series of that template's delivery and engagement rates over the window. Returned only when `limit` is 50 or fewer and the window is at most 90 days (trend_grain=daily) or 720 hours (trend_grain=hourly); a larger request returns 422. When `from` is omitted and `trend_grain=hourly`, the default start tightens to 29 days before `to`, keeping the window inside 720 hours, so a request built entirely from defaults always fits the cap.
7089
7681
  *
7090
7682
  */
7091
7683
  include_trend?: boolean;
@@ -7123,7 +7715,7 @@ type GetEmailStatsByLocationData = {
7123
7715
  */
7124
7716
  group_by?: "country" | "region" | "city";
7125
7717
  /**
7126
- * Metric to rank rows by, applied descending. Defaults to `unique_opens`. Only engagement counts are sortable; this breakdown has no rates.
7718
+ * Metric to rank rows by, applied descending. It defaults to `unique_opens`. Only engagement counts are sortable. This breakdown has no rates.
7127
7719
  *
7128
7720
  */
7129
7721
  sort?: EmailEngagementSortMetric;
@@ -7161,7 +7753,7 @@ type GetEmailStatsByClientData = {
7161
7753
  */
7162
7754
  group_by?: "email_client" | "os" | "device_type";
7163
7755
  /**
7164
- * Metric to rank rows by, applied descending. Defaults to `unique_opens`. Only engagement counts are sortable; this breakdown has no rates.
7756
+ * Metric to rank rows by, applied descending. It defaults to `unique_opens`. Only engagement counts are sortable. This breakdown has no rates.
7165
7757
  *
7166
7758
  */
7167
7759
  sort?: EmailEngagementSortMetric;
@@ -7190,11 +7782,11 @@ type GetEmailStatsByBounceCodeData = {
7190
7782
  */
7191
7783
  timezone?: string;
7192
7784
  /**
7193
- * Not supported on breakdown endpoints; supplying it returns 422. To compare categories use `GET /v1/email/stats/categories`; the summary, daily, and hourly statistics accept `category` as a filter.
7785
+ * Not supported on breakdown endpoints. Supplying it returns 422. To compare categories, use `GET /v1/email/stats/categories`. The summary, daily, and hourly statistics accept `category` as a filter.
7194
7786
  */
7195
7787
  category?: string;
7196
7788
  /**
7197
- * Metric to rank rows by, applied descending. Defaults to `bounced`. Only bounce counts are sortable; this breakdown has no rates.
7789
+ * Metric to rank rows by, applied descending. It defaults to `bounced`. Only the bounce counts are sortable here, because this breakdown has no rate fields.
7198
7790
  *
7199
7791
  */
7200
7792
  sort?: "bounced" | "bounces.hard" | "bounces.soft" | "bounces.admin" | "bounces.block" | "bounces.undetermined";
@@ -7223,11 +7815,11 @@ type GetEmailStatsByComplaintTypeData = {
7223
7815
  */
7224
7816
  timezone?: string;
7225
7817
  /**
7226
- * Not supported on breakdown endpoints; supplying it returns 422. To compare categories use `GET /v1/email/stats/categories`; the summary, daily, and hourly statistics accept `category` as a filter.
7818
+ * Not supported on breakdown endpoints. Supplying it returns 422. To compare categories, use `GET /v1/email/stats/categories`. The summary, daily, and hourly statistics accept `category` as a filter.
7227
7819
  */
7228
7820
  category?: string;
7229
7821
  /**
7230
- * Metric to rank rows by, applied descending. Defaults to `complained`, the only sortable metric for this breakdown.
7822
+ * Metric to rank rows by, applied descending. It defaults to `complained`, the only sortable metric for this breakdown.
7231
7823
  *
7232
7824
  */
7233
7825
  sort?: "complained";
@@ -7251,7 +7843,7 @@ type GetEmailStatsByBroadcastData = {
7251
7843
  */
7252
7844
  to?: string;
7253
7845
  /**
7254
- * Not supported on breakdown endpoints; supplying it returns 422. To compare categories use `GET /v1/email/stats/categories`; the summary, daily, and hourly statistics accept `category` as a filter.
7846
+ * Not supported on breakdown endpoints. Supplying it returns a 422. To compare categories, use `GET /v1/email/stats/categories`. The summary, daily, and hourly statistics accept `category` as a filter.
7255
7847
  */
7256
7848
  category?: string;
7257
7849
  /**
@@ -7306,15 +7898,16 @@ type CreateDomainData = {
7306
7898
  body: DomainCreate;
7307
7899
  headers?: {
7308
7900
  /**
7309
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
7901
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
7902
+ *
7310
7903
  * Two distinct 409 errors signal misuse:
7311
- * - `request_in_progress` (E01004): the same key is currently being
7312
- * processed by a concurrent request. Wait briefly and retry; the lock
7313
- * expires within 30 seconds.
7314
- * - `idempotency_key_reuse` (E01005): the same key has already completed
7904
+ *
7905
+ * - `request_in_progress` (E01004): The same key is currently being
7906
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
7907
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
7315
7908
  * against a different request body or method. Generate a new key.
7316
7909
  *
7317
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
7910
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
7318
7911
  *
7319
7912
  */
7320
7913
  "Idempotency-Key"?: string;
@@ -7327,15 +7920,16 @@ type UpdateDomainData = {
7327
7920
  body: DomainUpdate;
7328
7921
  headers?: {
7329
7922
  /**
7330
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
7923
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
7924
+ *
7331
7925
  * Two distinct 409 errors signal misuse:
7332
- * - `request_in_progress` (E01004): the same key is currently being
7333
- * processed by a concurrent request. Wait briefly and retry; the lock
7334
- * expires within 30 seconds.
7335
- * - `idempotency_key_reuse` (E01005): the same key has already completed
7926
+ *
7927
+ * - `request_in_progress` (E01004): The same key is currently being
7928
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
7929
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
7336
7930
  * against a different request body or method. Generate a new key.
7337
7931
  *
7338
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
7932
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
7339
7933
  *
7340
7934
  */
7341
7935
  "Idempotency-Key"?: string;
@@ -7370,7 +7964,7 @@ type ListMailboxesData = {
7370
7964
  */
7371
7965
  domain?: string;
7372
7966
  /**
7373
- * Include mailboxes deleted within their 30-day restore window. Defaults to false, so only active and suspended mailboxes are returned. Deleted mailboxes carry a non-null `deleted_at`.
7967
+ * Include mailboxes deleted within their 30-day restore window. Defaults to false, so only active and suspended mailboxes are returned. A deleted mailbox has a non-null `deleted_at`.
7374
7968
  */
7375
7969
  include_deleted?: boolean;
7376
7970
  /**
@@ -7392,15 +7986,16 @@ type CreateMailboxData = {
7392
7986
  body: MailboxCreate;
7393
7987
  headers?: {
7394
7988
  /**
7395
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
7989
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
7990
+ *
7396
7991
  * Two distinct 409 errors signal misuse:
7397
- * - `request_in_progress` (E01004): the same key is currently being
7398
- * processed by a concurrent request. Wait briefly and retry; the lock
7399
- * expires within 30 seconds.
7400
- * - `idempotency_key_reuse` (E01005): the same key has already completed
7992
+ *
7993
+ * - `request_in_progress` (E01004): The same key is currently being
7994
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
7995
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
7401
7996
  * against a different request body or method. Generate a new key.
7402
7997
  *
7403
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
7998
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
7404
7999
  *
7405
8000
  */
7406
8001
  "Idempotency-Key"?: string;
@@ -7413,15 +8008,16 @@ type UpdateMailboxData = {
7413
8008
  body: MailboxUpdate;
7414
8009
  headers?: {
7415
8010
  /**
7416
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
8011
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
8012
+ *
7417
8013
  * Two distinct 409 errors signal misuse:
7418
- * - `request_in_progress` (E01004): the same key is currently being
7419
- * processed by a concurrent request. Wait briefly and retry; the lock
7420
- * expires within 30 seconds.
7421
- * - `idempotency_key_reuse` (E01005): the same key has already completed
8014
+ *
8015
+ * - `request_in_progress` (E01004): The same key is currently being
8016
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
8017
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
7422
8018
  * against a different request body or method. Generate a new key.
7423
8019
  *
7424
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
8020
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
7425
8021
  *
7426
8022
  */
7427
8023
  "Idempotency-Key"?: string;
@@ -7434,7 +8030,7 @@ type UpdateMailboxData = {
7434
8030
  };
7435
8031
  query?: {
7436
8032
  /**
7437
- * Required as `true` when lowering `retention_tier`, acknowledging that remembered messages older than the new horizon are deleted.
8033
+ * Set to `true` when lowering `retention_tier` would delete remembered messages older than the new cutoff. The request is rejected without it in that case.
7438
8034
  */
7439
8035
  confirm?: boolean;
7440
8036
  };
@@ -7465,7 +8061,7 @@ type GetMailboxStatsData = {
7465
8061
  */
7466
8062
  timezone?: string;
7467
8063
  /**
7468
- * Bucket grain of the series: `day` (default) or `hour`. Echoed back as `period.grain`.
8064
+ * Granularity of the series: `day` (default) or `hour`. Echoed back as `period.grain`.
7469
8065
  *
7470
8066
  */
7471
8067
  granularity?: "day" | "hour";
@@ -7504,15 +8100,16 @@ type CreateMailboxReceiveRuleData = {
7504
8100
  body: ReceiveRuleCreate;
7505
8101
  headers?: {
7506
8102
  /**
7507
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
8103
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
8104
+ *
7508
8105
  * Two distinct 409 errors signal misuse:
7509
- * - `request_in_progress` (E01004): the same key is currently being
7510
- * processed by a concurrent request. Wait briefly and retry; the lock
7511
- * expires within 30 seconds.
7512
- * - `idempotency_key_reuse` (E01005): the same key has already completed
8106
+ *
8107
+ * - `request_in_progress` (E01004): The same key is currently being
8108
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
8109
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
7513
8110
  * against a different request body or method. Generate a new key.
7514
8111
  *
7515
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
8112
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
7516
8113
  *
7517
8114
  */
7518
8115
  "Idempotency-Key"?: string;
@@ -7539,15 +8136,17 @@ type ListEmailThreadsData = {
7539
8136
  */
7540
8137
  contact_id?: ContactId;
7541
8138
  /**
7542
- * Filter to conversations carrying this label. Repeat the parameter to require several only conversations carrying every listed label match. A placement label selects a folder (`inbox`, `archive`, `spam`, `blocked`); a custom label matches conversations in any folder. Defaults to `inbox` when omitted.
8139
+ * Filter to conversations that have this label. Repeat the parameter to ask for more than one: only conversations that have every label you list are returned.
8140
+ *
8141
+ * A placement label picks a folder: `inbox`, `archive`, `spam`, or `blocked`. A custom label matches a conversation in any folder. Leave this out and you get the inbox.
7543
8142
  */
7544
8143
  label?: Array<string>;
7545
8144
  /**
7546
- * When `true`, only conversations with unread messages are returned. This filters on the conversation's unread state, so it combines with `label` for example, unread conversations in the archive. (The `unread` label itself lives on messages, not conversations.)
8145
+ * When `true`, only conversations with unread messages are returned. This filters on the conversation's unread state, so you can combine it with `label`, for example to get unread conversations in the archive. The `unread` label itself lives on messages, not conversations.
7547
8146
  */
7548
8147
  has_unread?: boolean;
7549
8148
  /**
7550
- * Conversations involving this address matches the sender or any recipient, as a case-insensitive contains-match, so a full address or any fragment of one works.
8149
+ * Conversations involving this address, matching the sender or any recipient. The match is case-insensitive and matches on any part of the address, so a fragment works as well as the whole address.
7551
8150
  */
7552
8151
  participant?: string;
7553
8152
  /**
@@ -7581,15 +8180,16 @@ type DeleteEmailThreadData = {
7581
8180
  body?: never;
7582
8181
  headers?: {
7583
8182
  /**
7584
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
8183
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
8184
+ *
7585
8185
  * Two distinct 409 errors signal misuse:
7586
- * - `request_in_progress` (E01004): the same key is currently being
7587
- * processed by a concurrent request. Wait briefly and retry; the lock
7588
- * expires within 30 seconds.
7589
- * - `idempotency_key_reuse` (E01005): the same key has already completed
8186
+ *
8187
+ * - `request_in_progress` (E01004): The same key is currently being
8188
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
8189
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
7590
8190
  * against a different request body or method. Generate a new key.
7591
8191
  *
7592
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
8192
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
7593
8193
  *
7594
8194
  */
7595
8195
  "Idempotency-Key"?: string;
@@ -7612,15 +8212,16 @@ type UpdateEmailThreadData = {
7612
8212
  body: EmailThreadUpdateRequest;
7613
8213
  headers?: {
7614
8214
  /**
7615
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
8215
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
8216
+ *
7616
8217
  * Two distinct 409 errors signal misuse:
7617
- * - `request_in_progress` (E01004): the same key is currently being
7618
- * processed by a concurrent request. Wait briefly and retry; the lock
7619
- * expires within 30 seconds.
7620
- * - `idempotency_key_reuse` (E01005): the same key has already completed
8218
+ *
8219
+ * - `request_in_progress` (E01004): The same key is currently being
8220
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
8221
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
7621
8222
  * against a different request body or method. Generate a new key.
7622
8223
  *
7623
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
8224
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
7624
8225
  *
7625
8226
  */
7626
8227
  "Idempotency-Key"?: string;
@@ -7648,7 +8249,7 @@ type ListEmailThreadMessagesData = {
7648
8249
  */
7649
8250
  direction?: MessageDirection;
7650
8251
  /**
7651
- * Filter to messages carrying this label. `trash` lists trashed messages; any other label `archive`, `spam`, `blocked`, `unread`, or a custom label lists its non-trashed carriers. When omitted, received messages in the inbox and all sent messages are returned.
8252
+ * Filter to messages that have this label. `trash` lists trashed messages. Any other label, whether that is `archive`, `spam`, `blocked`, `unread` or one of your own, lists the messages that have it and are not in the trash. When omitted, received messages in the inbox and all sent messages are returned.
7652
8253
  *
7653
8254
  */
7654
8255
  label?: string;
@@ -7675,15 +8276,16 @@ type ReplyEmailThreadMessageData = {
7675
8276
  body: EmailThreadMessageReplyRequest;
7676
8277
  headers?: {
7677
8278
  /**
7678
- * Client-supplied deduplication key. When present, the server replays the original response for any duplicate request with the same key within the idempotency TTL window (3 hours by default).
8279
+ * Client-supplied deduplication key. When present, the original response is replayed for any duplicate request with the same key, within the idempotency window (3 hours by default).
8280
+ *
7679
8281
  * Two distinct 409 errors signal misuse:
7680
- * - `request_in_progress` (E01004): the same key is currently being
7681
- * processed by a concurrent request. Wait briefly and retry; the lock
7682
- * expires within 30 seconds.
7683
- * - `idempotency_key_reuse` (E01005): the same key has already completed
8282
+ *
8283
+ * - `request_in_progress` (E01004): The same key is currently being
8284
+ * processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.
8285
+ * - `idempotency_key_reuse` (E01005): The same key has already completed
7684
8286
  * against a different request body or method. Generate a new key.
7685
8287
  *
7686
- * Recommended key format is `<event-type>/<entity-id>` (e.g. `welcome-user/usr_abc123`).
8288
+ * Recommended key format is `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).
7687
8289
  *
7688
8290
  */
7689
8291
  "Idempotency-Key"?: string;
@@ -7723,12 +8325,12 @@ type ListVoiceCallsData = {
7723
8325
  */
7724
8326
  sip_trunk_id?: SipTrunkId;
7725
8327
  /**
7726
- * Return only calls placed from this calling party number, matched as a whole number rather than as a fragment. Give it in international form: `+14155551234`, `14155551234`, and `0014155551234` all select the same calls, because a call record keeps the number exactly as the calling equipment presented it. A number given without a country code matches only calls recorded in that same form, since it names a different number in every country. Use `number` instead to match part of a number, or either side of the call.
8328
+ * Return only calls placed from this calling party number, matched as a whole number rather than as a fragment. Give it in international form: `+14155551234`, `14155551234`, and `0014155551234` all select the same calls. A number given without a country code is read as an international one, so give the country code to be sure of what you are matching. Use `number` instead to match part of a number, or either side of the call.
7727
8329
  *
7728
8330
  */
7729
8331
  from?: string;
7730
8332
  /**
7731
- * Return only calls placed to this called party number, matched as a whole number rather than as a fragment. Give it in international form: `+16505559876`, `16505559876`, and `0016505559876` all select the same calls, because a call record keeps the number exactly as the calling equipment presented it. A number given without a country code matches only calls recorded in that same form, since it names a different number in every country. Use `number` instead to match part of a number, or either side of the call.
8333
+ * Return only calls placed to this called party number, matched as a whole number rather than as a fragment. Give it in international form: `+16505559876`, `16505559876`, and `0016505559876` all select the same calls. A number given without a country code is read as an international one, so give the country code to be sure of what you are matching. Use `number` instead to match part of a number, or either side of the call.
7732
8334
  *
7733
8335
  */
7734
8336
  to?: string;
@@ -8096,7 +8698,7 @@ declare abstract class Resource {
8096
8698
  type EmailListQuery$1 = NonNullable<ListEmailMessagesData["query"]>;
8097
8699
  declare class EmailResourceBase extends Resource {
8098
8700
  /**
8099
- * Fetch one email message by id, with aggregate delivery status and per-state recipient counts. The message body (html, text) is not returned. Per-recipient delivery statuses and the event log are separate sub-resources: GET /v1/email/messages/{message_id}/recipients and GET /v1/email/messages/{message_id}/events.
8701
+ * Fetch one email message by `id`, with aggregate delivery status and per-state recipient counts. The message body (`html`, `text`) is not returned. Per-recipient delivery statuses and the event log are separate sub-resources: `GET /v1/email/messages/{message_id}/recipients` and `GET /v1/email/messages/{message_id}/events`.
8100
8702
  *
8101
8703
  * @example
8102
8704
  * const msg = await bird.email.get("em_abc123");
@@ -8106,7 +8708,7 @@ declare class EmailResourceBase extends Resource {
8106
8708
  */
8107
8709
  get(messageId: string, options?: RequestOptions): APIPromise<EmailMessage>;
8108
8710
  /**
8109
- * List sent email messages, newest first, as a cursor page ({data, next_cursor, …}). Pass next_cursor back as starting_after to fetch the next page. Filter by creation time with the half-open range created_after (inclusive) / created_before (exclusive). For a single UTC day, created_after is that day at 00:00:00Z and created_before is the next day at 00:00:00Z.
8711
+ * List sent email messages, newest first, as a cursor page (`{data, next_cursor, …}`). Pass `next_cursor` back as `starting_after` to fetch the next page. Filter by creation time with the half-open range `created_after` (inclusive) and `created_before` (exclusive). For a single UTC day, `created_after` is that day at 00:00:00Z and `created_before` is the next day at 00:00:00Z.
8110
8712
  *
8111
8713
  * @example
8112
8714
  * for await (const message of bird.email.list({ status: "bounced" })) {
@@ -8115,7 +8717,7 @@ declare class EmailResourceBase extends Resource {
8115
8717
  */
8116
8718
  list(query?: EmailListQuery$1, options?: RequestOptions): PaginatedPromise<EmailMessage>;
8117
8719
  /**
8118
- * Cancel a scheduled email before it sends. Only works while the message is still scheduled (status `scheduled`); once it starts sending, or was already canceled, the call returns a conflict error. Canceling does not return consumed scheduled-send quota.
8720
+ * Cancel a scheduled email before it sends. Only works while the message's `status` is still `scheduled`. Once it starts sending, or was already canceled, the call returns a conflict error. Canceling does not return consumed scheduled-send quota.
8119
8721
  *
8120
8722
  * @example
8121
8723
  * await bird.email.cancel("em_abc123");
@@ -8142,7 +8744,7 @@ type EmailStatsByComplaintTypeQuery = NonNullable<GetEmailStatsByComplaintTypeDa
8142
8744
  type EmailStatsByBroadcastQuery = NonNullable<GetEmailStatsByBroadcastData["query"]>;
8143
8745
  declare class EmailStatsResource extends Resource {
8144
8746
  /**
8145
- * Aggregate email KPIs for one period: sends, delivered, bounces, complaints, opens, clicks, their rates, and latency percentiles. `from`/`to` are both YYYY-MM-DD days or both RFC 3339 instants (hour grain); add `compare=previous_period` for deltas versus the prior window. For a per-day or per-hour series use email_stats_daily or email_stats_hourly.
8747
+ * Aggregate email KPIs for one period: sends, delivered, bounces, complaints, opens, clicks, their rates, and latency percentiles. `from`/`to` are both YYYY-MM-DD days or both RFC 3339 instants (hour grain); add `compare=previous_period` for deltas versus the prior window. For a per-day or per-hour series use `email.stats.daily` or `email.stats.hourly`.
8146
8748
  *
8147
8749
  * @example Summary for a month
8148
8750
  * const s = await bird.email.stats.summary({ from: "2026-05-01", to: "2026-05-31" });
@@ -8150,7 +8752,7 @@ declare class EmailStatsResource extends Resource {
8150
8752
  */
8151
8753
  summary(query?: EmailStatsSummaryQuery, options?: RequestOptions): APIPromise<EmailStatsSummary>;
8152
8754
  /**
8153
- * Per-day email stats series (counts, rates, latency percentiles), gap-filled with zero rows, max 365 days. At most one filter of `category`, `sending_domain`, `tag`, `sending_ip`, `recipient_domain`, `template`. For hour resolution use email_stats_hourly; for one aggregate row use email_stats_summary.
8755
+ * Per-day email stats series (counts, rates, latency percentiles), gap-filled with zero rows, max 365 days. At most one filter of `category`, `sending_domain`, `tag`, `sending_ip`, `recipient_domain`, `template`. For hour resolution use `email.stats.hourly`; for one aggregate row use `email.stats.summary`.
8154
8756
  *
8155
8757
  * @example
8156
8758
  * const series = await bird.email.stats.daily({ from: "2026-05-01", to: "2026-05-31" });
@@ -8158,7 +8760,7 @@ declare class EmailStatsResource extends Resource {
8158
8760
  */
8159
8761
  daily(query?: EmailStatsDailyQuery, options?: RequestOptions): APIPromise<EmailStatsResponse>;
8160
8762
  /**
8161
- * Per-hour email stats series, gap-filled with zero rows, max 720 hours (30 days). Takes the same single-dimension filters as email_stats_daily; for longer ranges use email_stats_daily, for one aggregate row use email_stats_summary.
8763
+ * Per-hour email stats series, gap-filled with zero rows, max 720 hours (30 days). Takes the same single-dimension filters as `email.stats.daily`; for longer ranges use `email.stats.daily`, for one aggregate row use `email.stats.summary`.
8162
8764
  *
8163
8765
  * @example
8164
8766
  * const series = await bird.email.stats.hourly({ from: "2026-05-01", to: "2026-05-02" });
@@ -8166,7 +8768,7 @@ declare class EmailStatsResource extends Resource {
8166
8768
  */
8167
8769
  hourly(query?: EmailStatsHourlyQuery, options?: RequestOptions): APIPromise<EmailStatsResponse>;
8168
8770
  /**
8169
- * Email delivery and engagement stats grouped by tag, one row per `name:value` pair set at send time; ranked by `sort` (default `processed`). `include_trend=true` adds a per-bucket rate series to each row.
8771
+ * Email delivery and engagement stats grouped by tag, one row per `name:value` pair set at send time. Rows are ranked by `sort`, `processed` by default. Set `include_trend=true` to add a per-bucket rate series to each row.
8170
8772
  *
8171
8773
  * @example Top 10 tags by delivered
8172
8774
  * const { data } = await bird.email.stats.byTag({
@@ -8179,7 +8781,7 @@ declare class EmailStatsResource extends Resource {
8179
8781
  */
8180
8782
  byTag(query?: EmailStatsByTagQuery, options?: RequestOptions): APIPromise<EmailStatsTagsResponse>;
8181
8783
  /**
8182
- * Email delivery and engagement stats grouped by category (`transactional` versus `marketing`), ranked by `sort` (default `processed`). `include_trend=true` adds a per-bucket rate series to each row.
8784
+ * Email delivery and engagement stats grouped by category, meaning `transactional` compared with `marketing`. Rows are ranked by `sort`, `processed` by default. Set `include_trend=true` to add a per-bucket rate series to each row.
8183
8785
  *
8184
8786
  * @example
8185
8787
  * const { data } = await bird.email.stats.byCategory({ from: "2026-05-01", to: "2026-05-31" });
@@ -8187,7 +8789,7 @@ declare class EmailStatsResource extends Resource {
8187
8789
  */
8188
8790
  byCategory(query?: EmailStatsByCategoryQuery, options?: RequestOptions): APIPromise<EmailStatsByCategoryResponse>;
8189
8791
  /**
8190
- * Delivery and bounce stats grouped by sending IP; `sort=bounces.block` surfaces reputation-damaged IPs first. No engagement, complaint, or accepted/processed counts per IP; use email_stats_daily for workspace-wide figures.
8792
+ * Delivery and bounce stats grouped by sending IP, with deferral counts alongside them. `sort=bounces.block` surfaces reputation-damaged IPs first. Engagement, accepted, and processed counts aren't available per IP, and complaint and out-of-band bounce counts always read 0 here. For workspace-wide figures, use `email.stats.daily`.
8191
8793
  *
8192
8794
  * @example
8193
8795
  * const { data } = await bird.email.stats.bySendingIp({
@@ -8200,7 +8802,7 @@ declare class EmailStatsResource extends Resource {
8200
8802
  */
8201
8803
  bySendingIp(query?: EmailStatsBySendingIpQuery, options?: RequestOptions): APIPromise<EmailStatsBySendingIpResponse>;
8202
8804
  /**
8203
- * Email delivery and engagement stats grouped by sending (`From`) domain; compare deliverability across the workspace's verified domains. For per-IP reputation use email_stats_by_sending_ip.
8805
+ * Email delivery and engagement stats grouped by sending (`From`) domain, so you can compare deliverability across your workspace's verified domains. For per-IP reputation instead, use `email.stats.by_sending_ip`.
8204
8806
  *
8205
8807
  * @example
8206
8808
  * const { data } = await bird.email.stats.bySendingDomain({
@@ -8213,7 +8815,7 @@ declare class EmailStatsResource extends Resource {
8213
8815
  */
8214
8816
  bySendingDomain(query?: EmailStatsBySendingDomainQuery, options?: RequestOptions): APIPromise<EmailStatsBySendingDomainResponse>;
8215
8817
  /**
8216
- * Email delivery and engagement stats grouped by exact recipient mailbox domain (for example `gmail.com`). Finer-grained than email_stats_by_mailbox_provider, which buckets domains into providers.
8818
+ * Email delivery and engagement stats grouped by exact recipient mailbox domain, for example `gmail.com`. Finer-grained than `email.stats.by_mailbox_provider`, which buckets domains into providers.
8217
8819
  *
8218
8820
  * @example
8219
8821
  * const { data } = await bird.email.stats.byRecipientDomain({
@@ -8226,7 +8828,7 @@ declare class EmailStatsResource extends Resource {
8226
8828
  */
8227
8829
  byRecipientDomain(query?: EmailStatsByRecipientDomainQuery, options?: RequestOptions): APIPromise<EmailStatsByRecipientDomainResponse>;
8228
8830
  /**
8229
- * Email delivery and engagement stats grouped by recipient mailbox provider (`gmail`, `microsoft`, `yahoo`, ...); covers the delivery stage onward, no accepted/processed counts. For a per-region split use email_stats_by_mailbox_provider_region; for exact destination domains use email_stats_by_recipient_domain.
8831
+ * Email delivery and engagement stats grouped by recipient mailbox provider, for example `gmail`, `microsoft`, or `yahoo`. It covers the delivery stage onward, so there are no accepted or processed counts. For a per-region split within a provider, use `email.stats.by_mailbox_provider_region`; for exact destination domains instead, use `email.stats.by_recipient_domain`.
8230
8832
  *
8231
8833
  * @example
8232
8834
  * const { data } = await bird.email.stats.byMailboxProvider({
@@ -8238,7 +8840,7 @@ declare class EmailStatsResource extends Resource {
8238
8840
  */
8239
8841
  byMailboxProvider(query?: EmailStatsByMailboxProviderQuery, options?: RequestOptions): APIPromise<EmailStatsByMailboxProviderResponse>;
8240
8842
  /**
8241
- * Email delivery and engagement stats grouped by mailbox provider and provider region pair (for example `gmail` in `NA`); covers the delivery stage onward, no accepted/processed counts. For the provider-level view use email_stats_by_mailbox_provider.
8843
+ * Email delivery and engagement stats grouped by a mailbox provider and provider region pair, for example `gmail` in `NA`. It covers the delivery stage onward, so there are no accepted or processed counts. For the provider-level view without the region split, use `email.stats.by_mailbox_provider`.
8242
8844
  *
8243
8845
  * @example
8244
8846
  * const { data } = await bird.email.stats.byMailboxProviderRegion({
@@ -8250,7 +8852,7 @@ declare class EmailStatsResource extends Resource {
8250
8852
  */
8251
8853
  byMailboxProviderRegion(query?: EmailStatsByMailboxProviderRegionQuery, options?: RequestOptions): APIPromise<EmailStatsByMailboxProviderRegionResponse>;
8252
8854
  /**
8253
- * Email delivery and engagement stats grouped by the template used at send time, keyed by template id (`emt_…`); only templated sends appear. A single template's trend over time comes from email_stats_daily with its `template` filter.
8855
+ * Email delivery and engagement stats grouped by the template used at send time, keyed by template id (`emt_…`); only templated sends appear. A single template's trend over time comes from `email.stats.daily` with its `template` filter.
8254
8856
  *
8255
8857
  * @example
8256
8858
  * const { data } = await bird.email.stats.byTemplate({
@@ -8263,7 +8865,7 @@ declare class EmailStatsResource extends Resource {
8263
8865
  */
8264
8866
  byTemplate(query?: EmailStatsByTemplateQuery, options?: RequestOptions): APIPromise<EmailStatsByTemplateResponse>;
8265
8867
  /**
8266
- * Opens and clicks grouped by country, region, or city (`group_by`); engagement counts only, no delivery counts or rates. For engagement by mail client or device use email_stats_by_client.
8868
+ * Opens and clicks grouped by country, region, or city, whichever you choose with `group_by`. It only has engagement counts, no delivery counts or rates. For engagement grouped by mail client or device instead, use `email.stats.by_client`.
8267
8869
  *
8268
8870
  * @example
8269
8871
  * const { data } = await bird.email.stats.byLocation({
@@ -8275,7 +8877,7 @@ declare class EmailStatsResource extends Resource {
8275
8877
  */
8276
8878
  byLocation(query?: EmailStatsByLocationQuery, options?: RequestOptions): APIPromise<EmailStatsByLocationResponse>;
8277
8879
  /**
8278
- * Opens and clicks grouped by mail client, OS, or device type (`group_by`); engagement counts only, no delivery counts or rates. For engagement by geography use email_stats_by_location.
8880
+ * Opens and clicks grouped by mail client, operating system, or device type, whichever you choose with `group_by`. It only has engagement counts, no delivery counts or rates. For engagement grouped by geography instead, use `email.stats.by_location`.
8279
8881
  *
8280
8882
  * @example
8281
8883
  * const { data } = await bird.email.stats.byClient({
@@ -8287,7 +8889,7 @@ declare class EmailStatsResource extends Resource {
8287
8889
  */
8288
8890
  byClient(query?: EmailStatsByClientQuery, options?: RequestOptions): APIPromise<EmailStatsByClientResponse>;
8289
8891
  /**
8290
- * Bounce counts grouped by the SMTP error code the receiving server returned, with the hard/soft/admin/block/undetermined split; failure side only. It shows what is driving bounces, while bounces by destination come from email_stats_by_recipient_domain or email_stats_by_mailbox_provider.
8892
+ * Bounce counts grouped by the SMTP error code the receiving mail server returned. Each row also breaks the bounce down into its hard, soft, admin, block, and undetermined split. There are no delivered, open, or click counts here, because a bounce code only appears on a bounce event. For bounces broken down by destination instead, use `email.stats.by_recipient_domain` or `email.stats.by_mailbox_provider`.
8291
8893
  *
8292
8894
  * @example
8293
8895
  * const { data } = await bird.email.stats.byBounceCode({
@@ -8300,7 +8902,7 @@ declare class EmailStatsResource extends Resource {
8300
8902
  */
8301
8903
  byBounceCode(query?: EmailStatsByBounceCodeQuery, options?: RequestOptions): APIPromise<EmailStatsByBounceCodeResponse>;
8302
8904
  /**
8303
- * Spam-complaint counts grouped by the feedback-loop complaint type (for example `abuse`, `fraud`, `virus`); complaint side only. For complaints by destination use email_stats_by_mailbox_provider or email_stats_by_recipient_domain.
8905
+ * Spam-complaint counts grouped by the feedback-loop complaint type, for example `abuse`, `fraud`, or `virus`. Complaint side only, so there are no delivery or engagement counts. For complaints broken down by destination instead, use `email.stats.by_mailbox_provider` or `email.stats.by_recipient_domain`.
8304
8906
  *
8305
8907
  * @example
8306
8908
  * const { data } = await bird.email.stats.byComplaintType({ from: "2026-05-01", to: "2026-05-31" });
@@ -8308,7 +8910,7 @@ declare class EmailStatsResource extends Resource {
8308
8910
  */
8309
8911
  byComplaintType(query?: EmailStatsByComplaintTypeQuery, options?: RequestOptions): APIPromise<EmailStatsByComplaintTypeResponse>;
8310
8912
  /**
8311
- * Email delivery and engagement stats grouped by broadcast; only broadcast sends appear. Reflects roughly the last 30 days of activity.
8913
+ * Email delivery and engagement stats grouped by broadcast. Only broadcast sends appear. Reflects roughly the last 30 days of activity.
8312
8914
  *
8313
8915
  * @example
8314
8916
  * const { data } = await bird.email.stats.byBroadcast({
@@ -8339,7 +8941,7 @@ declare class EmailMailboxesResourceBase extends Resource {
8339
8941
  */
8340
8942
  list(query?: EmailMailboxesListQuery, options?: RequestOptions): PaginatedPromise<Mailbox>;
8341
8943
  /**
8342
- * Create a mailbox: a durable agent identity that owns an email address, groups mail into threads, and remembers conversations for its retention tier.
8944
+ * Create a mailbox: a durable agent identity that owns an email address, groups mail into conversations, and remembers conversations for its retention tier.
8343
8945
  *
8344
8946
  * @example Create a mailbox
8345
8947
  * const mailbox = await bird.email.mailboxes.create({ display_name: "Support" });
@@ -8347,7 +8949,7 @@ declare class EmailMailboxesResourceBase extends Resource {
8347
8949
  */
8348
8950
  create(params?: EmailMailboxesCreateParams, options?: RequestOptions): APIPromise<Mailbox>;
8349
8951
  /**
8350
- * Read one mailbox by id. A mailbox deleted within its 30-day restore window is still returned, carrying a non-null `deleted_at`; once that window closes it is gone and this returns 404.
8952
+ * Read one mailbox by ID. A mailbox deleted within its 30-day restore window is still returned, with a non-null `deleted_at`. Once that window closes it is gone and this returns 404.
8351
8953
  *
8352
8954
  * @example Get a mailbox
8353
8955
  * const mailbox = await bird.email.mailboxes.get("mbx_01abc");
@@ -8355,7 +8957,7 @@ declare class EmailMailboxesResourceBase extends Resource {
8355
8957
  */
8356
8958
  get(mailboxId: string, options?: RequestOptions): APIPromise<Mailbox>;
8357
8959
  /**
8358
- * Update a mailbox's display name, reply-to, receive policy, retention tier, IP pool, or metadata. Lowering the retention tier onto remembered messages older than the new horizon requires confirm=true.
8960
+ * Update a mailbox's display name, reply-to, receive policy, retention tier, IP pool, or metadata. Lowering the retention tier requires `confirm=true` when it would delete remembered messages older than the new cutoff.
8359
8961
  *
8360
8962
  * @example Change a mailbox's receive policy
8361
8963
  * const mailbox = await bird.email.mailboxes.update("mbx_01abc", {
@@ -8365,14 +8967,14 @@ declare class EmailMailboxesResourceBase extends Resource {
8365
8967
  */
8366
8968
  update(mailboxId: string, params?: EmailMailboxesUpdateParams, query?: EmailMailboxesUpdateQuery, options?: RequestOptions): APIPromise<Mailbox>;
8367
8969
  /**
8368
- * Delete a mailbox. The address stops receiving immediately and is quarantined; the mailbox and its remembered messages stay restorable for 30 days via the restore endpoint, then are permanently deleted.
8970
+ * Delete a mailbox. The address stops receiving immediately and is quarantined. The mailbox and its remembered messages stay restorable for 30 days through the restore endpoint, then are permanently deleted.
8369
8971
  *
8370
8972
  * @example Delete a mailbox
8371
8973
  * await bird.email.mailboxes.delete("mbx_01abc");
8372
8974
  */
8373
8975
  delete(mailboxId: string, options?: RequestOptions): APIPromise<void>;
8374
8976
  /**
8375
- * Restore a mailbox deleted less than 30 days ago: the address starts receiving again and the remembered messages are back. Past the window the mailbox is permanently deleted and returns 404; a mailbox that is not deleted returns 409.
8977
+ * Restore a mailbox deleted less than 30 days ago: the address starts receiving again and the remembered messages are back. Past the window the mailbox is permanently deleted and returns 404. A mailbox that is not deleted returns 409.
8376
8978
  *
8377
8979
  * @example Restore a deleted mailbox
8378
8980
  * const mailbox = await bird.email.mailboxes.restore("mbx_01abc");
@@ -8380,7 +8982,7 @@ declare class EmailMailboxesResourceBase extends Resource {
8380
8982
  */
8381
8983
  restore(mailboxId: string, options?: RequestOptions): APIPromise<Mailbox>;
8382
8984
  /**
8383
- * Reactivate a suspended mailbox so it can send and receive again and its threads become visible. Fails if your plan does not have room for another active mailbox (or another custom inbox.ai handle); delete an active mailbox or upgrade first. A mailbox that is not suspended returns 409.
8985
+ * Resume a suspended mailbox so it can send and receive again and its conversations become visible. Fails if your plan does not have room for another active mailbox (or another custom inbox.ai handle). Delete an active mailbox or upgrade first. A mailbox that is not suspended returns 409.
8384
8986
  *
8385
8987
  * @example Resume a suspended mailbox
8386
8988
  * const mailbox = await bird.email.mailboxes.resume("mbx_01abc");
@@ -8436,7 +9038,7 @@ declare class EmailMailboxesReceiveRulesResource extends Resource {
8436
9038
  */
8437
9039
  list(mailboxId: string, query?: EmailMailboxesReceiveRulesListQuery, options?: RequestOptions): PaginatedPromise<ReceiveRule>;
8438
9040
  /**
8439
- * Add an allow or block rule for a sender address or domain to a mailbox. Block always wins; up to 200 rules per mailbox.
9041
+ * Add an allow or block rule for a sender address or domain to a mailbox. Block always wins. Up to 200 rules per mailbox.
8440
9042
  *
8441
9043
  * @example Block a domain
8442
9044
  * const rule = await bird.email.mailboxes.receiveRules.create("mbx_01abc", {
@@ -8510,7 +9112,7 @@ type EmailThreadsMessagesListQuery = NonNullable<ListEmailThreadMessagesData["qu
8510
9112
  type EmailThreadsMessagesReplyParams = NonNullable<ReplyEmailThreadMessageData["body"]>;
8511
9113
  declare class EmailThreadsMessagesResource extends Resource {
8512
9114
  /**
8513
- * List the messages in a conversation newest first, both directions. Page older messages with starting_after, and pass include=extracted_text to inline each message's durable plain text.
9115
+ * List the messages in a conversation newest first, both directions. Page older messages with starting_after, and pass include=extracted_text to inline each message's extracted plain text.
8514
9116
  *
8515
9117
  * @example List a thread's messages
8516
9118
  * for await (const msg of bird.email.threads.messages.list("thr_01abc")) {
@@ -8519,7 +9121,7 @@ declare class EmailThreadsMessagesResource extends Resource {
8519
9121
  */
8520
9122
  list(threadId: string, query?: EmailThreadsMessagesListQuery, options?: RequestOptions): PaginatedPromise<EmailThreadMessage>;
8521
9123
  /**
8522
- * Get one conversation message with its extracted plain text, readable for the mailbox's full retention period without MIME parsing.
9124
+ * Get one conversation message with its extracted plain text, readable for the mailbox's full retention tier without MIME parsing.
8523
9125
  *
8524
9126
  * @example Get a message
8525
9127
  * const msg = await bird.email.threads.messages.get("thr_01abc", "rem_01xyz");
@@ -8527,7 +9129,7 @@ declare class EmailThreadsMessagesResource extends Resource {
8527
9129
  */
8528
9130
  get(threadId: string, messageId: string, options?: RequestOptions): APIPromise<EmailThreadMessage>;
8529
9131
  /**
8530
- * Get the original rendered HTML and plain-text body of a conversation message. Available 30 days; after that use the message's extracted_text.
9132
+ * Get the original rendered HTML and plain-text body of a conversation message. Available for 30 days. After that, use the message's extracted_text.
8531
9133
  *
8532
9134
  * @example Get a message body
8533
9135
  * const body = await bird.email.threads.messages.body("thr_01abc", "rem_01xyz");
@@ -8545,7 +9147,7 @@ declare class EmailThreadsMessagesResource extends Resource {
8545
9147
  */
8546
9148
  reply(threadId: string, messageId: string, params?: EmailThreadsMessagesReplyParams, options?: RequestOptions): APIPromise<EmailThreadMessage>;
8547
9149
  /**
8548
- * List the attachments on a conversation message. Bytes are downloadable for 30 days; the metadata also rides the message's attachment_manifest durably.
9150
+ * List the attachments on a conversation message. Bytes are downloadable for 30 days, and the metadata stays readable afterward on the message's attachment_manifest.
8549
9151
  *
8550
9152
  * @example List a message's attachments
8551
9153
  * const atts = await bird.email.threads.messages.attachments("thr_01abc", "rem_01xyz");
@@ -8605,6 +9207,29 @@ declare class EmailResource<D extends EmailChannelDefaults | undefined = undefin
8605
9207
  * });
8606
9208
  * console.log(msg.id, msg.status); // "em_…", "accepted"
8607
9209
  *
9210
+ * @example Send a published template instead of inline content
9211
+ * const msg = await bird.email.send({
9212
+ * from: { email: "onboarding@messagebird.dev", name: "Bird" },
9213
+ * to: ["delivered@messagebird.dev"],
9214
+ * category: "transactional",
9215
+ * template: {
9216
+ * slug: "welcome-email",
9217
+ * parameters: { first_name: "Jane" },
9218
+ * },
9219
+ * });
9220
+ * console.log(msg.id, msg.status);
9221
+ *
9222
+ * @example Sending to the sandbox bounce address, which hard-bounces every time
9223
+ * const msg = await bird.email.send({
9224
+ * from: { email: "onboarding@messagebird.dev", name: "Bird" },
9225
+ * to: ["bounce+signup-flow@messagebird.dev"],
9226
+ * subject: "Sandbox bounce test",
9227
+ * html: "<p>This message will hard-bounce.</p>",
9228
+ * tags: [{ name: "flow", value: "signup" }],
9229
+ * metadata: { test_run: "docs-capture-1" },
9230
+ * });
9231
+ * console.log(msg.id, msg.status); // "em_…", "accepted"
9232
+ *
8608
9233
  * @example A richer send — cc/bcc, reply-to, tags, metadata, click-tracking off, and an idempotency key (safe to retry; the server dedupes)
8609
9234
  * await bird.email.send(
8610
9235
  * {
@@ -8736,7 +9361,7 @@ declare class AudiencesResource extends Resource {
8736
9361
  */
8737
9362
  listContacts(audienceId: string, query?: AudienceListContactsQuery, options?: RequestOptions): PaginatedPromise<AudienceMember>;
8738
9363
  /**
8739
- * Add up to 1,000 existing contacts to a static audience by ID. Fails entirely if any contact ID does not exist.
9364
+ * Add up to 1,000 existing contacts to a static audience by ID. Fails entirely if any contact ID does not exist. To add contacts you have not created yet, use `contacts.batch` with `audience_ids` instead: it matches or creates each contact by email address and assigns it to the audience in one call.
8740
9365
  *
8741
9366
  * @example Add contacts to an audience
8742
9367
  * await bird.audiences.addContacts("adn_01krdgeqcxet5s7t44vh8rt9mg", {
@@ -8804,7 +9429,7 @@ declare class DomainsResource extends Resource {
8804
9429
  */
8805
9430
  verify(domainId: string, options?: RequestOptions): APIPromise<Domain>;
8806
9431
  /**
8807
- * Update a sending domain's tracking and inbound configuration. Tracking: click_tracking and open_tracking apply immediately to new sends, and the tracking domain can be set, changed, or removed (the name part only; Bird appends the sending domain). Enabling either toggle with no tracking domain configured returns 409, and removing the tracking domain while either toggle is still on also returns 409. Tracking-domain changes on a verified domain are staged behind DNS verification, so the current config keeps serving until the new records verify. Inbound receiving: inbound.enabled starts or stops receiving mail for the domain. Enabling requires the domain's DKIM to be verified first (a fresh enable on an unverified domain returns 422), and a domain already receiving inbound for another organization returns 422. The MX records to publish are always listed in dns_records regardless, so receiving starts only once inbound.enabled is set, even when those records are already published.
9432
+ * Update a sending domain's tracking and inbound configuration. Tracking: click_tracking and open_tracking apply immediately to new sends, and the tracking domain can be set, changed, or removed (the name part only, and the sending domain is appended for you). Enabling either toggle with no tracking domain configured returns 409, and removing the tracking domain while either toggle is still on also returns 409. Tracking-domain changes on a verified domain are staged behind DNS verification, so the current config keeps serving until the new records verify. Inbound receiving: inbound.enabled starts or stops receiving mail for the domain. Enabling requires the domain's DKIM to be verified first (a fresh enable on an unverified domain returns 422), and a domain already receiving inbound for another organization returns 422. The MX records to publish are always listed in dns_records regardless, so receiving starts only once inbound.enabled is set, even when those records are already published.
8808
9433
  *
8809
9434
  * @example Enable tracking on a domain
8810
9435
  * await bird.domains.update("dom_01krdgeqcxet5s7t44vh8rt9mg", {
@@ -8884,7 +9509,7 @@ type ContactUpdateParams = NonNullable<UpdateContactData["body"]>;
8884
9509
  type ContactBatchParams = NonNullable<CreateContactBatchData["body"]>;
8885
9510
  declare class ContactsResource extends Resource {
8886
9511
  /**
8887
- * List the workspace's contacts as a cursor page, newest first. Look one up by exact email, phone, or external_id, or search by email, name, or phone substring. Pass include_total for a total count.
9512
+ * List the workspace's contacts as a cursor page, newest first. Look one up by exact email, phone_number, or external_id, repeating phone_number to resolve up to 50 numbers in one call (raise limit to match), or search by email, name, or phone substring. Pass include_total for a total count.
8888
9513
  *
8889
9514
  * @example Iterate every contact, or take one page
8890
9515
  * for await (const contact of bird.contacts.list({ q: "acme.com" })) {
@@ -8894,7 +9519,7 @@ declare class ContactsResource extends Resource {
8894
9519
  */
8895
9520
  list(query?: ContactListQuery, options?: RequestOptions): PaginatedPromise<Contact>;
8896
9521
  /**
8897
- * Get a single contact by ID (`con_`-prefixed). Look up an ID by exact email, phone, or external_id with `contacts.list`.
9522
+ * Get a single contact by ID (`con_`-prefixed). Look up an ID by exact email, phone_number, or external_id with `contacts.list`.
8898
9523
  *
8899
9524
  * @example Fetch a contact by id
8900
9525
  * const contact = await bird.contacts.get("con_01krdgeqcxet5s7t44vh8rt9mg");
@@ -8902,7 +9527,7 @@ declare class ContactsResource extends Resource {
8902
9527
  */
8903
9528
  get(contactId: string, options?: RequestOptions): APIPromise<Contact>;
8904
9529
  /**
8905
- * Create a contact identified by an email address, an E.164 phone number, or both. Fails with a conflict if the email, phone, or external_id is already used by another contact. For bulk import or create-or-update semantics use `contacts.batch`.
9530
+ * Create a contact identified by an email address, an E.164 phone number, or both. Fails with a conflict if the email, phone_number, or external_id is already used by another contact. For bulk import or create-or-update semantics use `contacts.batch`.
8906
9531
  *
8907
9532
  * @example Create a contact
8908
9533
  * const contact = await bird.contacts.create({
@@ -8913,7 +9538,7 @@ declare class ContactsResource extends Resource {
8913
9538
  */
8914
9539
  create(params?: ContactCreateParams, options?: RequestOptions): APIPromise<Contact>;
8915
9540
  /**
8916
- * Update a contact's name, external_id, email, phone, or custom data. Only supplied fields change; custom data keys are merged, with null removing a key. A contact keeps at least one identifier: clearing both email and phone is rejected.
9541
+ * Update a contact's name, external_id, email, phone_number, or custom data. Only supplied fields change; custom data keys are merged, with null removing a key. A contact keeps at least one identifier: clearing both email and phone_number is rejected.
8917
9542
  *
8918
9543
  * @example Change a contact's fields
8919
9544
  * const contact = await bird.contacts.update("con_01krdgeqcxet5s7t44vh8rt9mg", {
@@ -8930,7 +9555,7 @@ declare class ContactsResource extends Resource {
8930
9555
  */
8931
9556
  delete(contactId: string, options?: RequestOptions): APIPromise<void>;
8932
9557
  /**
8933
- * Create or update up to 1,000 contacts in one request, each entry matched automatically against every identifier it supplies (email, phone, external_id) or, with match_on, by that one field only, and optionally add them all to one or more audiences. Per-contact results are returned in submission order.
9558
+ * Create or update up to 1,000 contacts in one request, each entry matched automatically against every identifier it supplies (email, phone_number, external_id) or, with match_on, by that one field only, and optionally add them all to one or more audiences. Per-contact results are returned in submission order.
8934
9559
  *
8935
9560
  * @example Create or update many contacts at once, matched by the identifiers each entry carries
8936
9561
  * const result = await bird.contacts.batch({
@@ -8976,7 +9601,7 @@ type SmsSendBatchResult = SmsMessageBatchResponse;
8976
9601
  declare class SmsResource extends SmsResourceBase {
8977
9602
  /**
8978
9603
  * Send one SMS to a single recipient. Supply either `text` (with a `category`)
8979
- * or a stored `template` (by `id` or `name`, with its `parameters`). The
9604
+ * or a stored `template` (by `id` or `slug`, with its `parameters`). The
8980
9605
  * result is `accepted`, not yet delivered — read it back with `get` to confirm.
8981
9606
  *
8982
9607
  * @example Send free text
@@ -8991,7 +9616,7 @@ declare class SmsResource extends SmsResourceBase {
8991
9616
  * @example Send by template
8992
9617
  * await bird.sms.send({
8993
9618
  * to: "+14155550100",
8994
- * template: { name: "bird_otp_verification", parameters: { code: "123456" } },
9619
+ * template: { slug: "bird_otp_verification", parameters: { code: "123456" } },
8995
9620
  * });
8996
9621
  */
8997
9622
  send(params: SmsSendParams, options?: RequestOptions): APIPromise<SmsMessage>;
@@ -9016,13 +9641,13 @@ declare class SmsTemplatesResource extends Resource {
9016
9641
  *
9017
9642
  * @example List the built-in templates
9018
9643
  * const { data } = await bird.smsTemplates.list({ scope: "system" });
9019
- * for (const tpl of data) console.log(tpl.id, tpl.name);
9644
+ * for (const tpl of data) console.log(tpl.id, tpl.slug);
9020
9645
  */
9021
9646
  list(query?: SmsTemplateListQuery, options?: RequestOptions): APIPromise<SmsTemplateList>;
9022
9647
  /**
9023
- * Get one SMS template by its name or id, including its body and the variables it expects. Fetch it before sms_send to see which parameter keys a template send requires.
9648
+ * Get one SMS template by its slug or id, including its body and the variables it expects. Fetch it before sms_send to see which parameter keys a template send requires.
9024
9649
  *
9025
- * @example Read one template by name or id
9650
+ * @example Read one template by slug or id
9026
9651
  * const tpl = await bird.smsTemplates.get("bird_otp_verification");
9027
9652
  * console.log(tpl.body, tpl.variables);
9028
9653
  */
@@ -9075,9 +9700,7 @@ declare class WhatsappResource extends WhatsappResourceBase {
9075
9700
  * to: "+15551234567",
9076
9701
  * template: {
9077
9702
  * slug: "bird_otp",
9078
- * components: [
9079
- * { type: "body", parameters: [{ type: "text", text: "123456" }] },
9080
- * ],
9703
+ * components: [{ type: "body", parameters: [{ type: "text", text: "123456" }] }],
9081
9704
  * },
9082
9705
  * });
9083
9706
  * console.log(msg.id, msg.status);
@@ -9114,7 +9737,7 @@ type VerifyVerificationsCheckParams = NonNullable<CreateVerificationCheckData["b
9114
9737
  type VerifyVerificationsNextChannelParams = NonNullable<CreateVerificationNextChannelData["body"]>;
9115
9738
  declare class VerifyVerificationsResource extends Resource {
9116
9739
  /**
9117
- * Start a verification: generate a one-time passcode and send it to the recipient in `to` (a phone number over the phone channels enabled for its destination country; an email address over email; or both). It is sent over one channel at a time and fails over to the next in the plan, never over two at once. Calling again for the same recipient reuses the in-progress verification and sends a fresh code after the resend cooldown; it does not start a second one, so use this both to send and to resend. The passcode is never returned; submit what the recipient enters with verify_verifications_check. SMS delivery draws on the workspace's SMS balance.
9740
+ * Start a verification: generate a one-time passcode and send it to the recipient in `to` (a phone number over the phone channels enabled for its destination country; an email address over email; or both). It is sent over one channel at a time and fails over to the next in the plan, never over two at once. Calling again for the same recipient reuses the in-progress verification and sends a fresh code after the resend cooldown; it does not start a second one, so use this both to send and to resend. The passcode is never returned; submit what the recipient enters with verify_verifications_check. SMS, WhatsApp and Telegram delivery all draw on the workspace's balance.
9118
9741
  *
9119
9742
  * @example Start a verification over SMS
9120
9743
  * const verification = await bird.verify.verifications.create({
@@ -9304,6 +9927,34 @@ declare class RealtimeResource extends RealtimeResourceBase {
9304
9927
  constructor(core: ConstructorParameters<typeof Resource>[0], client: ConstructorParameters<typeof Resource>[1]);
9305
9928
  }
9306
9929
  //#endregion
9930
+ //#region src/resources/lookup.gen.d.ts
9931
+ type LookupPhoneNumberParams = NonNullable<CreatePhoneNumberLookupData["body"]>;
9932
+ type LookupEmailParams = NonNullable<CreateEmailLookupData["body"]>;
9933
+ declare class LookupResource extends Resource {
9934
+ /**
9935
+ * Look up what a phone number is. Returns the serving network, the issuing network, whether the number was ported, its country, and its line type, free with every call. Pass `type` to buy extra blocks: `classification` (the allocated service of the range, from an intelligence source, reported beside the free `line_type` rather than replacing it), `porting` (whether the number ever moved network, when, and its full history), `presence` (reachable on the network right now), `roaming`, `sim_swap` (when the SIM last changed), and `score` (0-100 credibility). Every requested block reports its own status, and only the ones reading `ok` are billed on top of the lookup. Nothing is sent to the number.
9936
+ *
9937
+ * @example Look up a number, buying two extra blocks
9938
+ * const answer = await bird.lookup.phoneNumber({
9939
+ * phone_number: "+31612345678",
9940
+ * type: ["classification", "score"],
9941
+ * });
9942
+ * console.log(answer.country_code, answer.line_type);
9943
+ * // Only a block whose status is ok carries a value, and only that one is billed.
9944
+ * if (answer.score?.status === "ok") console.log(answer.score.value);
9945
+ */
9946
+ phoneNumber(params: LookupPhoneNumberParams, options?: RequestOptions): APIPromise<PhoneNumberLookup>;
9947
+ /**
9948
+ * Look up whether an email address is worth sending to. Returns `result` (the verdict: `valid`; `neutral`, meaning it could not be confirmed either way; `risky`, meaning it will probably accept mail but is likelier than most to bounce or complain; `undeliverable`; or `typo`), `delivery_confidence` (0-100), `flags` (`role`, `disposable`, `free_provider`), `reason` on an undeliverable address (`invalid_syntax`, `invalid_domain`, `invalid_recipient`), and `did_you_mean` when the address looks like a misspelling of a real one. `result` and `reason` are OPEN vocabularies: the values listed here are today's and more may be added, so treat an unrecognized value as a future one rather than an error, falling back on `delivery_confidence`. One address per call. Every answered lookup is billed the same flat amount whatever the verdict, so treat it as a paid call rather than a free check, and use an `Idempotency-Key` so a retry does not buy a second answer. Nothing is sent to the address.
9949
+ *
9950
+ * @example Check whether an address is worth sending to
9951
+ * const answer = await bird.lookup.email({ email: "aisha.khan@example.com" });
9952
+ * // result is an open vocabulary; delivery_confidence is always comparable.
9953
+ * console.log(answer.result, answer.delivery_confidence);
9954
+ */
9955
+ email(params: LookupEmailParams, options?: RequestOptions): APIPromise<EmailLookup>;
9956
+ }
9957
+ //#endregion
9307
9958
  //#region src/client.d.ts
9308
9959
  interface BirdClientOptions {
9309
9960
  apiKey: string;
@@ -9402,6 +10053,8 @@ declare class BirdClient<const O extends BirdClientOptions = BirdClientOptions>
9402
10053
  readonly contactProperties: ContactPropertiesResource;
9403
10054
  /** Sending domains — `bird.domains.create(...)`, `.list(...)`, `.verify(...)`, … */
9404
10055
  readonly domains: DomainsResource;
10056
+ /** Recipient intelligence — `bird.lookup.email(...)`, `.phoneNumber(...)`. Every answer is billed. */
10057
+ readonly lookup: LookupResource;
9405
10058
  /** Webhooks — `bird.webhooks.unwrap(payload, headers)` verifies an inbound delivery. */
9406
10059
  readonly webhooks: WebhooksResource;
9407
10060
  /** Realtime — `bird.realtime.publish(...)`, `.channels.list(...)`, `.members.disconnect(...)`, … */
@@ -9509,6 +10162,66 @@ declare const EmailEventType: {
9509
10162
  };
9510
10163
  /** A known EmailEventType value. */
9511
10164
  type EmailEventTypeValue = (typeof EmailEventType)[keyof typeof EmailEventType];
10165
+ /**
10166
+ * Values of EmailLookupFlag known at this SDK version. The wire value is an open
10167
+ * string: a value added by a newer server deserializes unchanged, so switch on
10168
+ * these with a `default` branch rather than treating the set as closed.
10169
+ */
10170
+ declare const EmailLookupFlag: {
10171
+ readonly Disposable: "disposable";
10172
+ readonly FreeProvider: "free_provider";
10173
+ readonly Role: "role";
10174
+ };
10175
+ /** A known EmailLookupFlag value. */
10176
+ type EmailLookupFlagValue = (typeof EmailLookupFlag)[keyof typeof EmailLookupFlag];
10177
+ /**
10178
+ * Values of EmailLookupReason known at this SDK version. The wire value is an open
10179
+ * string: a value added by a newer server deserializes unchanged, so switch on
10180
+ * these with a `default` branch rather than treating the set as closed.
10181
+ */
10182
+ declare const EmailLookupReason: {
10183
+ readonly InvalidDomain: "invalid_domain";
10184
+ readonly InvalidRecipient: "invalid_recipient";
10185
+ readonly InvalidSyntax: "invalid_syntax";
10186
+ };
10187
+ /** A known EmailLookupReason value. */
10188
+ type EmailLookupReasonValue = (typeof EmailLookupReason)[keyof typeof EmailLookupReason];
10189
+ /**
10190
+ * Values of EmailLookupResult known at this SDK version. The wire value is an open
10191
+ * string: a value added by a newer server deserializes unchanged, so switch on
10192
+ * these with a `default` branch rather than treating the set as closed.
10193
+ */
10194
+ declare const EmailLookupResult: {
10195
+ readonly Neutral: "neutral";
10196
+ readonly Risky: "risky";
10197
+ readonly Typo: "typo";
10198
+ readonly Undeliverable: "undeliverable";
10199
+ readonly Valid: "valid";
10200
+ };
10201
+ /** A known EmailLookupResult value. */
10202
+ type EmailLookupResultValue = (typeof EmailLookupResult)[keyof typeof EmailLookupResult];
10203
+ /**
10204
+ * Values of LookupFlag known at this SDK version. The wire value is an open
10205
+ * string: a value added by a newer server deserializes unchanged, so switch on
10206
+ * these with a `default` branch rather than treating the set as closed.
10207
+ */
10208
+ declare const LookupFlag: {
10209
+ readonly Ported: "ported";
10210
+ };
10211
+ /** A known LookupFlag value. */
10212
+ type LookupFlagValue = (typeof LookupFlag)[keyof typeof LookupFlag];
10213
+ /**
10214
+ * Values of LookupPropertyStatus known at this SDK version. The wire value is an open
10215
+ * string: a value added by a newer server deserializes unchanged, so switch on
10216
+ * these with a `default` branch rather than treating the set as closed.
10217
+ */
10218
+ declare const LookupPropertyStatus: {
10219
+ readonly Inconclusive: "inconclusive";
10220
+ readonly Ok: "ok";
10221
+ readonly Unavailable: "unavailable";
10222
+ };
10223
+ /** A known LookupPropertyStatus value. */
10224
+ type LookupPropertyStatusValue = (typeof LookupPropertyStatus)[keyof typeof LookupPropertyStatus];
9512
10225
  /**
9513
10226
  * Values of SMSErrorCode known at this SDK version. The wire value is an open
9514
10227
  * string: a value added by a newer server deserializes unchanged, so switch on
@@ -9529,6 +10242,32 @@ declare const SMSErrorCode: {
9529
10242
  };
9530
10243
  /** A known SMSErrorCode value. */
9531
10244
  type SMSErrorCodeValue = (typeof SMSErrorCode)[keyof typeof SMSErrorCode];
10245
+ /**
10246
+ * Values of TemplateLanguageStatus known at this SDK version. The wire value is an open
10247
+ * string: a value added by a newer server deserializes unchanged, so switch on
10248
+ * these with a `default` branch rather than treating the set as closed.
10249
+ */
10250
+ declare const TemplateLanguageStatus: {
10251
+ readonly Draft: "draft";
10252
+ readonly Live: "live";
10253
+ readonly Superseded: "superseded";
10254
+ };
10255
+ /** A known TemplateLanguageStatus value. */
10256
+ type TemplateLanguageStatusValue = (typeof TemplateLanguageStatus)[keyof typeof TemplateLanguageStatus];
10257
+ /**
10258
+ * Values of TemplateStatus known at this SDK version. The wire value is an open
10259
+ * string: a value added by a newer server deserializes unchanged, so switch on
10260
+ * these with a `default` branch rather than treating the set as closed.
10261
+ */
10262
+ declare const TemplateStatus: {
10263
+ readonly Active: "active";
10264
+ readonly Draft: "draft";
10265
+ readonly Inactive: "inactive";
10266
+ readonly Pending: "pending";
10267
+ readonly Rejected: "rejected";
10268
+ };
10269
+ /** A known TemplateStatus value. */
10270
+ type TemplateStatusValue = (typeof TemplateStatus)[keyof typeof TemplateStatus];
9532
10271
  /**
9533
10272
  * Values of VerificationAttemptFailureReason known at this SDK version. The wire value is an open
9534
10273
  * string: a value added by a newer server deserializes unchanged, so switch on
@@ -9553,6 +10292,7 @@ type VerificationAttemptFailureReasonValue = (typeof VerificationAttemptFailureR
9553
10292
  declare const VerificationChannel: {
9554
10293
  readonly Email: "email";
9555
10294
  readonly Sms: "sms";
10295
+ readonly Telegram: "telegram";
9556
10296
  readonly Whatsapp: "whatsapp";
9557
10297
  };
9558
10298
  /** A known VerificationChannel value. */
@@ -9584,6 +10324,21 @@ declare const WhatsAppErrorCode: {
9584
10324
  };
9585
10325
  /** A known WhatsAppErrorCode value. */
9586
10326
  type WhatsAppErrorCodeValue = (typeof WhatsAppErrorCode)[keyof typeof WhatsAppErrorCode];
10327
+ /**
10328
+ * Values of WhatsAppEventType known at this SDK version. The wire value is an open
10329
+ * string: a value added by a newer server deserializes unchanged, so switch on
10330
+ * these with a `default` branch rather than treating the set as closed.
10331
+ */
10332
+ declare const WhatsAppEventType: {
10333
+ readonly WhatsappAccepted: "whatsapp.accepted";
10334
+ readonly WhatsappDelivered: "whatsapp.delivered";
10335
+ readonly WhatsappFailed: "whatsapp.failed";
10336
+ readonly WhatsappRead: "whatsapp.read";
10337
+ readonly WhatsappRejected: "whatsapp.rejected";
10338
+ readonly WhatsappSent: "whatsapp.sent";
10339
+ };
10340
+ /** A known WhatsAppEventType value. */
10341
+ type WhatsAppEventTypeValue = (typeof WhatsAppEventType)[keyof typeof WhatsAppEventType];
9587
10342
  /**
9588
10343
  * Values of WhatsAppTemplateCategory known at this SDK version. The wire value is an open
9589
10344
  * string: a value added by a newer server deserializes unchanged, so switch on
@@ -9612,5 +10367,5 @@ declare const WhatsAppTemplateParameterType: {
9612
10367
  /** A known WhatsAppTemplateParameterType value. */
9613
10368
  type WhatsAppTemplateParameterTypeValue = (typeof WhatsAppTemplateParameterType)[keyof typeof WhatsAppTemplateParameterType];
9614
10369
  //#endregion
9615
- export { type APIPromise, type Audience, type AudienceAddContactsParams, type AudienceCreateParams, type AudienceListContactsQuery, type AudienceListQuery, type AudienceMember, type AudienceRemoveContactsParams, type AudienceUpdateParams, 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 Contact, type ContactBatchParams, type ContactCreateParams, type ContactListQuery, type ContactProperty, type ContactPropertyCreateParams, type ContactPropertyListQuery, type ContactPropertyUpdateParams, type ContactUpdateParams, type ContactUpsertResult, type CursorPage, type DnsRecord, type Domain, type DomainCapabilities, type DomainCreateParams, type DomainDkim, type DomainListQuery, type DomainUpdateParams, type EmailChannelDefaults, EmailEventType, type EmailEventTypeValue, type EmailListQuery, type EmailMailboxLabelList, type EmailMailboxesCreateParams, type EmailMailboxesListQuery, type EmailMailboxesMessagesCreateParams, type EmailMailboxesReceiveRulesCreateParams, type EmailMailboxesReceiveRulesListQuery, type EmailMailboxesStatsQuery, type EmailMailboxesUpdateParams, type EmailMailboxesUpdateQuery, type EmailMessage, type EmailSendBatchParams, type EmailSendBatchResult, type EmailSendParams, type EmailStatsByBounceCodeQuery, type EmailStatsByBounceCodeResponse, type EmailStatsByBroadcastQuery, type EmailStatsByBroadcastResponse, type EmailStatsByCategoryQuery, type EmailStatsByCategoryResponse, type EmailStatsByClientQuery, type EmailStatsByClientResponse, type EmailStatsByComplaintTypeQuery, type EmailStatsByComplaintTypeResponse, type EmailStatsByLocationQuery, type EmailStatsByLocationResponse, type EmailStatsByMailboxProviderQuery, type EmailStatsByMailboxProviderRegionQuery, type EmailStatsByMailboxProviderRegionResponse, type EmailStatsByMailboxProviderResponse, type EmailStatsByRecipientDomainQuery, type EmailStatsByRecipientDomainResponse, type EmailStatsBySendingDomainQuery, type EmailStatsBySendingDomainResponse, type EmailStatsBySendingIpQuery, type EmailStatsBySendingIpResponse, type EmailStatsByTagQuery, type EmailStatsByTemplateQuery, type EmailStatsByTemplateResponse, type EmailStatsDailyQuery, type EmailStatsHourlyQuery, type EmailStatsResponse, type EmailStatsSummary, type EmailStatsSummaryQuery, type EmailStatsTagsResponse, type EmailThread, type EmailThreadMessage, type EmailThreadMessageAttachmentList, type EmailThreadMessageBody, type EmailThreadsDeleteQuery, type EmailThreadsListQuery, type EmailThreadsMessagesListQuery, type EmailThreadsMessagesReplyParams, type EmailThreadsUpdateParams, type ErrorDetail, type ErrorNextAction, type Mailbox, type MailboxStatsResponse, type PaginatedPromise, type RealtimeBatchPublishResult, type RealtimeChannelGetQuery, type RealtimeChannelInclude, type RealtimeChannelInfo, type RealtimeChannelListItem, type RealtimeChannelListQuery, type RealtimeChannelMember, type RealtimeChannelMembers, type RealtimeChannelsList, type RealtimeOptions, type RealtimePublishBatchParams, type RealtimePublishParams, type RealtimePublishResult, type ReceiveRule, type RequestOptions, SMSErrorCode, type SMSErrorCodeValue, type SafeResult, type SmsListQuery, type SmsMessage, type SmsSendBatchParams, type SmsSendBatchResult, type SmsSendParams, type SmsTemplate, type SmsTemplateList, type SmsTemplateListQuery, type UnmetGate, type Verification, VerificationAttemptFailureReason, type VerificationAttemptFailureReasonValue, VerificationChannel, type VerificationChannelValue, type VerificationCheckResult, VerificationTerminalReason, type VerificationTerminalReasonValue, type VerifyVerificationsCheckParams, type VerifyVerificationsCreateParams, type VerifyVerificationsNextChannelParams, WebhookEventType, type WebhookEventTypeValue, type WebhookHeaders, type WebhookOptions, WhatsAppErrorCode, type WhatsAppErrorCodeValue, type WhatsAppEventList, type WhatsAppMessage, WhatsAppTemplateCategory, type WhatsAppTemplateCategoryValue, WhatsAppTemplateParameterType, type WhatsAppTemplateParameterTypeValue, type WhatsappListEventsQuery, type WhatsappListQuery, type WhatsappSendParams, baseUrlForRegion, regionFromApiKey };
10370
+ export { type APIPromise, type Audience, type AudienceAddContactsParams, type AudienceCreateParams, type AudienceListContactsQuery, type AudienceListQuery, type AudienceMember, type AudienceRemoveContactsParams, type AudienceUpdateParams, 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 Contact, type ContactBatchParams, type ContactCreateParams, type ContactListQuery, type ContactProperty, type ContactPropertyCreateParams, type ContactPropertyListQuery, type ContactPropertyUpdateParams, type ContactUpdateParams, type ContactUpsertResult, type CursorPage, type DnsRecord, type Domain, type DomainCapabilities, type DomainCreateParams, type DomainDkim, type DomainListQuery, type DomainUpdateParams, type EmailChannelDefaults, EmailEventType, type EmailEventTypeValue, type EmailListQuery, type EmailLookup, EmailLookupFlag, type EmailLookupFlagValue, EmailLookupReason, type EmailLookupReasonValue, EmailLookupResult, type EmailLookupResultValue, type EmailMailboxLabelList, type EmailMailboxesCreateParams, type EmailMailboxesListQuery, type EmailMailboxesMessagesCreateParams, type EmailMailboxesReceiveRulesCreateParams, type EmailMailboxesReceiveRulesListQuery, type EmailMailboxesStatsQuery, type EmailMailboxesUpdateParams, type EmailMailboxesUpdateQuery, type EmailMessage, type EmailSendBatchParams, type EmailSendBatchResult, type EmailSendParams, type EmailStatsByBounceCodeQuery, type EmailStatsByBounceCodeResponse, type EmailStatsByBroadcastQuery, type EmailStatsByBroadcastResponse, type EmailStatsByCategoryQuery, type EmailStatsByCategoryResponse, type EmailStatsByClientQuery, type EmailStatsByClientResponse, type EmailStatsByComplaintTypeQuery, type EmailStatsByComplaintTypeResponse, type EmailStatsByLocationQuery, type EmailStatsByLocationResponse, type EmailStatsByMailboxProviderQuery, type EmailStatsByMailboxProviderRegionQuery, type EmailStatsByMailboxProviderRegionResponse, type EmailStatsByMailboxProviderResponse, type EmailStatsByRecipientDomainQuery, type EmailStatsByRecipientDomainResponse, type EmailStatsBySendingDomainQuery, type EmailStatsBySendingDomainResponse, type EmailStatsBySendingIpQuery, type EmailStatsBySendingIpResponse, type EmailStatsByTagQuery, type EmailStatsByTemplateQuery, type EmailStatsByTemplateResponse, type EmailStatsDailyQuery, type EmailStatsHourlyQuery, type EmailStatsResponse, type EmailStatsSummary, type EmailStatsSummaryQuery, type EmailStatsTagsResponse, type EmailThread, type EmailThreadMessage, type EmailThreadMessageAttachmentList, type EmailThreadMessageBody, type EmailThreadsDeleteQuery, type EmailThreadsListQuery, type EmailThreadsMessagesListQuery, type EmailThreadsMessagesReplyParams, type EmailThreadsUpdateParams, type ErrorDetail, type LookupEmailParams, LookupFlag, type LookupFlagValue, type LookupPhoneNumberParams, LookupPropertyStatus, type LookupPropertyStatusValue, type Mailbox, type MailboxStatsResponse, type NextAction, type PaginatedPromise, type PhoneNumberLookup, type RealtimeBatchPublishResult, type RealtimeChannelGetQuery, type RealtimeChannelInclude, type RealtimeChannelInfo, type RealtimeChannelListItem, type RealtimeChannelListQuery, type RealtimeChannelMember, type RealtimeChannelMembers, type RealtimeChannelsList, type RealtimeOptions, type RealtimePublishBatchParams, type RealtimePublishParams, type RealtimePublishResult, type ReceiveRule, type RequestOptions, SMSErrorCode, type SMSErrorCodeValue, type SafeResult, type SmsListQuery, type SmsMessage, type SmsSendBatchParams, type SmsSendBatchResult, type SmsSendParams, type SmsTemplate, type SmsTemplateList, type SmsTemplateListQuery, TemplateLanguageStatus, type TemplateLanguageStatusValue, TemplateStatus, type TemplateStatusValue, type UnmetGate, type Verification, VerificationAttemptFailureReason, type VerificationAttemptFailureReasonValue, VerificationChannel, type VerificationChannelValue, type VerificationCheckResult, VerificationTerminalReason, type VerificationTerminalReasonValue, type VerifyVerificationsCheckParams, type VerifyVerificationsCreateParams, type VerifyVerificationsNextChannelParams, WebhookEventType, type WebhookEventTypeValue, type WebhookHeaders, type WebhookOptions, WhatsAppErrorCode, type WhatsAppErrorCodeValue, type WhatsAppEventList, WhatsAppEventType, type WhatsAppEventTypeValue, type WhatsAppMessage, WhatsAppTemplateCategory, type WhatsAppTemplateCategoryValue, WhatsAppTemplateParameterType, type WhatsAppTemplateParameterTypeValue, type WhatsappListEventsQuery, type WhatsappListQuery, type WhatsappSendParams, baseUrlForRegion, regionFromApiKey };
9616
10371
  //# sourceMappingURL=index.d.mts.map