openapi: 3.2.0 info: title: Bird Email Mailboxes API version: 1.0.0 description: 'The Bird API: one REST API for email, SMS, WhatsApp, verification, and Realtime.' servers: - url: https://{region}.platform.bird.com description: 'Regional API endpoint. Use the host for the region your organization is hosted in. Official Bird SDKs and the CLI select it automatically from your API key, so you rarely need to set it by hand. ' variables: region: default: us1 enum: - us1 - eu1 description: The region your organization's data is hosted in. - url: https://platform.bird.com description: Region-independent endpoint for authentication and account administration. - url: http://localhost:8080 description: Local development. security: - BearerAuth: [] tags: - name: email-mailboxes description: Durable mailbox identities for agents. A mailbox owns an address, applies receive policy through allow/block rules, and remembers conversations for its retention tier. paths: /v1/email/mailboxes: get: operationId: listMailboxes summary: List mailboxes description: Returns a paginated list of the workspace's mailboxes, newest first. Search across addresses and display names with `q`, look a mailbox up by its exact address, or filter by lifecycle state or domain. tags: - email-mailboxes security: - BearerAuth: [] - CookieAuth: [] x-audiences: - public - command x-snippet-key: email.mailboxes.list parameters: - name: address in: query required: false description: Filter to the mailbox with exactly this address. schema: type: string format: email minLength: 5 example: concierge@inbox.ai - name: q in: query required: false description: Case-insensitive search matching the mailbox's address or display name (substring). schema: type: string minLength: 1 maxLength: 320 example: concierge - name: state in: query required: false description: Return only `active` or `suspended` mailboxes. Use `include_deleted` for restorable deleted mailboxes. schema: type: string enum: - active - suspended - name: domain in: query required: false description: Filter to mailboxes whose address is on this domain. schema: type: string minLength: 1 example: inbox.ai - name: include_deleted in: query required: false description: Include mailboxes deleted within their 30-day restore window. Defaults to false, so only active and suspended mailboxes are returned. A deleted mailbox has `deleted_at` set. schema: type: boolean default: false - $ref: '#/components/parameters/PaginationLimit' - $ref: '#/components/parameters/StartingAfter' - $ref: '#/components/parameters/EndingBefore' responses: '200': description: Paginated list of mailboxes. content: application/json: schema: $ref: '#/components/schemas/MailboxList' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '422': $ref: '#/components/responses/Unprocessable' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' x-surfaces: - cli - make - mcp - n8n - sdk post: operationId: createMailbox summary: Create a mailbox description: Creates a mailbox. The address is `local_part@domain`. The domain defaults to `inbox.ai`, Bird's shared mailbox domain, where creating the mailbox claims the address for your organization. It is first come, first served, and reserved to your organization even after the mailbox is deleted. You may instead name one of your own domains that is enabled for receiving email. An omitted local part is generated. On a custom domain, addresses of deleted mailboxes are quarantined for 30 days and remain reserved for your workspace. tags: - email-mailboxes security: - BearerAuth: [] - CookieAuth: [] x-audiences: - public - command x-snippet-key: email.mailboxes.create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: examples: mailbox-open: summary: An agent mailbox that accepts mail from anyone value: display_name: My Agent receive_policy: open schema: $ref: '#/components/schemas/MailboxCreate' responses: '201': description: Mailbox created. headers: Idempotency-Replay: $ref: '#/components/headers/IdempotencyReplay' content: application/json: schema: $ref: '#/components/schemas/Mailbox' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '409': $ref: '#/components/responses/Conflict' '422': $ref: '#/components/responses/Unprocessable' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-surfaces: - cli - make - mcp - n8n - sdk /v1/email/mailboxes/{mailbox_id}: parameters: - name: mailbox_id in: path required: true description: Mailbox identifier. Starts with `mbx_`. schema: $ref: '#/components/schemas/MailboxID' get: operationId: getMailbox summary: Get a mailbox description: Returns a single mailbox by ID. A mailbox deleted within its 30-day restore window is still returned, with `deleted_at` set. Once the window closes it is permanently removed and returns `404`. tags: - email-mailboxes security: - BearerAuth: [] - CookieAuth: [] x-audiences: - public - command x-snippet-key: email.mailboxes.get responses: '200': description: Mailbox object. content: application/json: schema: $ref: '#/components/schemas/Mailbox' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/Unprocessable' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' x-surfaces: - cli - make - mcp - n8n - sdk patch: operationId: updateMailbox summary: Update a mailbox description: Updates a mailbox. The address and domain are immutable. Lowering the retention tier makes remembered messages older than the new cutoff eligible for deletion. If any exist, the request requires `confirm=true`. A tier change is applied to the mailbox's stored messages in the background; lowering the tier again while that is still being applied is refused with `E17050`. You can still raise it to a tier your plan permits. tags: - email-mailboxes security: - BearerAuth: [] - CookieAuth: [] x-audiences: - public - command x-snippet-key: email.mailboxes.update parameters: - $ref: '#/components/parameters/IdempotencyKey' - name: confirm in: query required: false description: Set to `true` when lowering `retention_tier` would make remembered messages older than the new cutoff eligible for deletion. The request is rejected without it in that case. schema: type: boolean default: false requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/MailboxUpdate' responses: '200': description: Mailbox updated. content: application/json: schema: $ref: '#/components/schemas/Mailbox' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '402': $ref: '#/components/responses/PaymentRequired' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '422': $ref: '#/components/responses/Unprocessable' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-surfaces: - cli - make - mcp - n8n - sdk delete: operationId: deleteMailbox summary: Delete a mailbox description: Deletes a mailbox. The address stops receiving mail immediately and enters quarantine. After 30 days, your workspace can bind the address to a new mailbox; the address remains reserved to your workspace. You can restore the mailbox for 30 days with `POST /email/mailboxes/{mailbox_id}/restore`. Normal message-retention expiry continues during that period. After 30 days, the mailbox and its remaining messages are permanently deleted. Returns `409` (`E01028`) if an enabled inbound route targets the mailbox. Disable, delete, or redirect those routes before retrying. tags: - email-mailboxes security: - BearerAuth: [] - CookieAuth: [] x-audiences: - public - command x-snippet-key: email.mailboxes.delete parameters: - $ref: '#/components/parameters/IdempotencyKey' responses: '204': description: Mailbox deleted. '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '422': $ref: '#/components/responses/Unprocessable' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-surfaces: - cli - make - mcp - n8n - sdk /v1/email/mailboxes/{mailbox_id}/restore: parameters: - name: mailbox_id in: path required: true description: Mailbox identifier. Starts with `mbx_`. schema: $ref: '#/components/schemas/MailboxID' post: operationId: restoreMailbox summary: Restore a deleted mailbox description: Restores receiving and access to unexpired messages. Returns `404` if deletion was 30 or more days ago or permanent erasure has started, and `409` if the mailbox is not deleted or its address is unavailable. tags: - email-mailboxes security: - BearerAuth: [] - CookieAuth: [] x-audiences: - public - command x-snippet-key: email.mailboxes.restore parameters: - $ref: '#/components/parameters/IdempotencyKey' responses: '200': description: Mailbox restored. headers: Idempotency-Replay: $ref: '#/components/headers/IdempotencyReplay' content: application/json: schema: $ref: '#/components/schemas/Mailbox' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '422': $ref: '#/components/responses/Unprocessable' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-surfaces: - cli - make - mcp - n8n - sdk /v1/email/mailboxes/{mailbox_id}/stats: parameters: - name: mailbox_id in: path required: true description: Mailbox identifier. Starts with `mbx_`. schema: $ref: '#/components/schemas/MailboxID' get: operationId: getMailboxStats summary: Get mailbox email statistics description: 'Returns the mailbox''s sent and received email statistics over a time window: a period-wide summary plus a bucketed series. Sent-mail metrics have the same delivery, engagement, and latency breakdowns as the email stats endpoints. `received` counts mail that arrived at the mailbox. Rows are bucketed by the time the event happened rather than the time the message was sent, so engagement that arrived during the period for a message sent earlier is counted here. Statistics start when the mailbox starts sending and receiving; the mailbox''s all-time `message_count` and `thread_count` live on the mailbox resource itself. `from` and `to` accept either calendar days (`YYYY-MM-DD`, `day` granularity only) or RFC 3339 instants (`hour` granularity only). Both bounds must use the same form. Window caps depend on `granularity`: 365 days at `day`, 30 days at `hour`. Set `timezone` to report in a local zone instead of UTC.' tags: - email-mailboxes security: - BearerAuth: [] - CookieAuth: [] x-audiences: - public - command x-snippet-key: email.mailboxes.stats parameters: - name: from in: query required: false description: 'Inclusive start of the window: a calendar day (`YYYY-MM-DD`, `day` granularity only) or an RFC 3339 instant rounded down to the hour (`hour` granularity only). Interpreted in `timezone`, or in UTC when `timezone` is omitted. A numeric UTC offset is rejected when `timezone` is set; use a calendar day or a `Z` (UTC) instant. Must use the same form as `to`. Defaults to 30 days before `to` at `day` granularity and 7 days before `to` at `hour`, when omitted. ' schema: type: string minLength: 1 pattern: ^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2}))?$ example: '2026-07-01' - name: to in: query required: false description: 'Inclusive end of the window: a calendar day (`YYYY-MM-DD`, `day` granularity only) or an RFC 3339 instant rounded down to the hour (`hour` granularity only). Interpreted in `timezone`, or in UTC when `timezone` is omitted. A numeric UTC offset is rejected when `timezone` is set; use a calendar day or a `Z` (UTC) instant. Must use the same form as `from`. Defaults to today (day) or the current hour (hour) in that timezone when omitted. Window may not exceed 365 days at `day` or 30 days at `hour` granularity. ' schema: type: string minLength: 1 pattern: ^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2}))?$ example: '2026-07-21' - $ref: '#/components/parameters/StatsTimezone' - name: granularity in: query required: false description: 'Granularity of the series: `day` (default) or `hour`. Echoed back as `period.grain`. ' schema: type: string enum: - day - hour default: day responses: '200': description: The mailbox's sent and received email statistics for the requested period. content: application/json: schema: $ref: '#/components/schemas/MailboxStatsResponse' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/Unprocessable' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-surfaces: - cli - make - mcp - n8n - sdk /v1/email/mailboxes/{mailbox_id}/resume: parameters: - name: mailbox_id in: path required: true description: Mailbox identifier. Starts with `mbx_`. schema: $ref: '#/components/schemas/MailboxID' post: operationId: resumeMailbox summary: Resume a suspended mailbox description: Resumes a mailbox that was suspended because the organization dropped below the plan needed to keep it active. The mailbox can send and receive again and its conversations and messages become visible. Resuming is refused when the organization has no room for another active mailbox, or for another custom inbox.ai handle, on its current plan. Free up a slot by deleting an active mailbox, or move to a bigger plan. Resuming a mailbox that is not suspended returns a conflict. tags: - email-mailboxes security: - BearerAuth: [] - CookieAuth: [] x-audiences: - public - command x-snippet-key: email.mailboxes.resume parameters: - $ref: '#/components/parameters/IdempotencyKey' responses: '200': description: Mailbox activated. headers: Idempotency-Replay: $ref: '#/components/headers/IdempotencyReplay' content: application/json: schema: $ref: '#/components/schemas/Mailbox' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '422': $ref: '#/components/responses/Unprocessable' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-surfaces: - cli - make - mcp - n8n - sdk /v1/email/mailboxes/{mailbox_id}/receive-rules: parameters: - name: mailbox_id in: path required: true description: Mailbox identifier. Starts with `mbx_`. schema: $ref: '#/components/schemas/MailboxID' get: operationId: listMailboxReceiveRules summary: List receive rules description: Returns a paginated list of the mailbox's receive rules, oldest first. Filter by action to see only allow or only block entries. tags: - email-mailboxes security: - BearerAuth: [] - CookieAuth: [] x-audiences: - public - command x-snippet-key: email.mailboxes.receive_rules.list parameters: - name: action in: query required: false description: Return only `allow` or `block` rules; omit to return both actions. schema: type: string enum: - allow - block - $ref: '#/components/parameters/PaginationLimit' - $ref: '#/components/parameters/StartingAfter' - $ref: '#/components/parameters/EndingBefore' responses: '200': description: Paginated list of receive rules. content: application/json: schema: $ref: '#/components/schemas/ReceiveRuleList' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/Unprocessable' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' x-surfaces: - cli - make - mcp - n8n - sdk post: operationId: createMailboxReceiveRule summary: Create a receive rule description: Adds an allow or block rule to the mailbox. Rules match the message's envelope sender. Domain entries also match subdomains. Block rules always win, both over allow rules and over the reply admission on allowlist mailboxes. An entry is either allow or block. Rules have no update operation, so a rule that needs the other action is a new rule and the old one is removed. A mailbox holds up to 200 rules. tags: - email-mailboxes security: - BearerAuth: [] - CookieAuth: [] x-audiences: - public - command x-snippet-key: email.mailboxes.receive_rules.create parameters: - $ref: '#/components/parameters/IdempotencyKey' requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ReceiveRuleCreate' responses: '201': description: Receive rule created. headers: Idempotency-Replay: $ref: '#/components/headers/IdempotencyReplay' content: application/json: schema: $ref: '#/components/schemas/ReceiveRule' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '409': $ref: '#/components/responses/Conflict' '422': $ref: '#/components/responses/Unprocessable' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-surfaces: - cli - make - mcp - n8n - sdk /v1/email/mailboxes/{mailbox_id}/receive-rules/{rule_id}: parameters: - name: mailbox_id in: path required: true description: Mailbox identifier. Starts with `mbx_`. schema: $ref: '#/components/schemas/MailboxID' - name: rule_id in: path required: true description: Receive-rule identifier. Starts with `erl_`. schema: $ref: '#/components/schemas/ReceiveRuleID' delete: operationId: deleteMailboxReceiveRule summary: Delete a receive rule description: Removes a receive rule from the mailbox. A rule's allow or block action cannot be changed after creation; delete it and create a replacement. tags: - email-mailboxes security: - BearerAuth: [] - CookieAuth: [] x-audiences: - public - command x-snippet-key: email.mailboxes.receive_rules.delete parameters: - $ref: '#/components/parameters/IdempotencyKey' responses: '204': description: Receive rule deleted. '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': $ref: '#/components/responses/NotFound' '422': $ref: '#/components/responses/Unprocessable' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/InternalError' '503': $ref: '#/components/responses/ServiceUnavailable' x-surfaces: - cli - make - mcp - n8n - sdk components: parameters: PaginationLimit: name: limit in: query required: false description: Maximum number of items to return per page. schema: type: integer minimum: 1 maximum: 100 default: 25 StatsTimezone: name: timezone in: query required: false description: 'IANA timezone identifier used to group statistics, for example `Asia/Kathmandu`. The default is UTC. Day and hour boundaries, including the default window when `from` and `to` are omitted, follow this timezone. When this parameter is set, pass `from` and `to` as calendar days or `Z` instants instead of timestamps with explicit UTC offsets. ' schema: type: string minLength: 1 example: Asia/Kathmandu IdempotencyKey: name: Idempotency-Key in: header required: false description: "Client-supplied key. On operations supporting request deduplication, a retained\nresponse is replayed for duplicate requests with the same key within the\nidempotency window (3 hours by default). This protection requires a workspace,\norganization, or staff-account scope. User-only and unauthenticated operations,\nstreams, and operations with a separate replay contract do not use this\nresponse replay.\n\nOn a supported operation, if idempotency protection is unavailable before execution, the API returns\n`503 IdempotencyUnavailable` (E01033) without executing this attempt. Retry with\nbackoff using the same key and request. An operation that takes effect before\nits response is retained can still execute again on retry.\n\nTwo distinct 409 errors signal misuse:\n\n- `request_in_progress` (E01004): The same key is currently being\n processed by a concurrent request. Wait briefly and retry. The lock expires within 30 seconds.\n- `idempotency_key_reuse` (E01005): The same key has already completed\n against a different request body or method. Generate a new key.\n\nRecommended key format is `/` (for example `welcome-user/usr_abc123`).\n" schema: type: string maxLength: 255 StartingAfter: name: starting_after in: query required: false description: Cursor from the `next_cursor` field of a previous list response. Returns items immediately after the cursor position in the current sort order. schema: type: string EndingBefore: name: ending_before in: query required: false description: Cursor from the `prev_cursor` or `refresh_cursor` field of a previous list response. Returns items immediately before the cursor position in the current sort order. `prev_cursor` returns the preceding page. `refresh_cursor` anchors at the first row of that response, which on a newest-first sort is how to fetch the items that have appeared since. schema: type: string schemas: ErrorBody: type: object additionalProperties: false required: - type - code - name - message - doc_url - request_id properties: type: type: string minLength: 1 description: Broad category for coarse client branching. enum: - auth_error - bad_request_error - billing_error - conflict_error - gone_error - internal_error - misdirected_error - not_found_error - not_implemented_error - payload_too_large_error - permission_error - precondition_error - rate_limit_error - service_unavailable_error - too_early_error - validation_error code: type: string minLength: 1 pattern: ^E\d{5}$ description: Opaque, stable, unique error identifier. Never reused. name: type: string minLength: 1 description: Human-readable slug for log readability. Paired with code, never replaces it. message: type: string minLength: 1 description: Human-readable description. Not stable; clients must not parse it. param: type: string minLength: 1 description: Identifies the offending field. Omitted when not applicable. doc_url: type: string minLength: 1 format: uri description: Stable link to the docs page for this error code. request_id: type: string minLength: 1 description: Request correlation ID for support and troubleshooting. Also returned in the `X-Request-Id` response header. vendor_code: type: string minLength: 1 description: 'Verbatim error code from an external system, such as an SMTP response code or a payment decline code. Present only when the code may help you resolve the error. ' details: type: array description: Per-field validation errors. Present only on validation_error responses. items: $ref: '#/components/schemas/ErrorDetail' remediation: type: string minLength: 1 description: A human-readable next step to resolve this error. Present when a recovery is known. next: type: array description: 'The steps that resolve this error. Perform them in order, re-reading after each; a `wait` or `terminal` step is always last. Present for errors with a well-defined recovery, such as unmet preconditions and conflicts. ' items: $ref: '#/components/schemas/NextAction' MailboxList: allOf: - type: object required: - data properties: data: type: array items: $ref: '#/components/schemas/Mailbox' - $ref: '#/components/schemas/_ListEnvelope' EmailBounceStatsWithRates: type: object additionalProperties: false readOnly: true description: 'Breakdown of `bounced` by failure type, with each rate as a fraction of `bounced`. Counts are distinct bounced recipients of that type; the five types approximately partition `bounced`, so the five rates sum to roughly 1.0 when `bounced` is non-zero. ' required: - hard - soft - admin - block - undetermined - hard_rate - soft_rate - admin_rate - block_rate - undetermined_rate properties: hard: type: integer minimum: 0 readOnly: true description: Distinct recipients with a permanent delivery failure (invalid address or non-existent domain). example: 12410 soft: type: integer minimum: 0 readOnly: true description: Distinct recipients with a transient delivery failure (mailbox full or server temporarily unavailable). example: 14290 admin: type: integer minimum: 0 readOnly: true description: Distinct recipients refused by a policy at the receiving end, such as relaying denied or a blocklisted domain. example: 410 block: type: integer minimum: 0 readOnly: true description: Distinct recipients bounced because the receiving mail server blocked the sending IP for reputation reasons. example: 920 undetermined: type: integer minimum: 0 readOnly: true description: Distinct recipients bounced where the receiving server's response did not allow precise classification. example: 80 hard_rate: type: - number - 'null' minimum: 0 maximum: 1 readOnly: true description: 'Fraction of bounced recipients that hard bounced, computed as `hard / bounced`. Null when `bounced` is zero. ' example: 0.454 soft_rate: type: - number - 'null' minimum: 0 maximum: 1 readOnly: true description: 'Fraction of bounced recipients that soft bounced, computed as `soft / bounced`. Null when `bounced` is zero. ' example: 0.523 admin_rate: type: - number - 'null' minimum: 0 maximum: 1 readOnly: true description: 'Fraction of bounced recipients that admin bounced, computed as `admin / bounced`. Null when `bounced` is zero. ' example: 0.015 block_rate: type: - number - 'null' minimum: 0 maximum: 1 readOnly: true description: 'Fraction of bounced recipients that block bounced, computed as `block / bounced`. Null when `bounced` is zero. ' example: 0.0337 undetermined_rate: type: - number - 'null' minimum: 0 maximum: 1 readOnly: true description: 'Fraction of bounced recipients with undetermined classification, computed as `undetermined / bounced`. Null when `bounced` is zero. ' example: 0.0029 ReceiveRuleList: allOf: - type: object required: - data properties: data: type: array items: $ref: '#/components/schemas/ReceiveRule' - $ref: '#/components/schemas/_ListEnvelope' EmailEngagementStats: type: object additionalProperties: false readOnly: true description: '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. An event counts in the time bucket when it occurs, even if the message was sent in an earlier bucket. 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. ' required: - opens - opens_non_prefetched - unique_opens - unique_opens_non_prefetched - clicks - unique_clicks - unsubscribes - open_rate - click_rate - unsubscribe_rate properties: opens: type: integer minimum: 0 readOnly: true description: 'Distinct open events, counting repeat opens from the same recipient and opens auto-fetched by inbox privacy features (such as Apple Mail Privacy Protection and the Gmail image proxy). ' example: 5420 opens_non_prefetched: type: integer minimum: 0 readOnly: true description: 'Distinct open events excluding those auto-fetched by inbox privacy features. Same event-counting semantics as `opens` (repeat opens from the same recipient count separately), with prefetched opens removed. ' example: 3210 unique_opens: type: integer minimum: 0 readOnly: true description: Distinct recipients who opened at least once, including opens auto-fetched by inbox privacy features. example: 3640 unique_opens_non_prefetched: type: integer minimum: 0 readOnly: true description: 'Distinct recipients who opened at least once, excluding opens auto-fetched by inbox privacy features. This is the numerator used for open rate, so iOS-heavy audiences (Apple Mail Privacy Protection and similar) do not inflate it. ' example: 2480 clicks: type: integer minimum: 0 readOnly: true description: Distinct click events, counting repeat clicks from the same recipient. example: 924 unique_clicks: type: integer minimum: 0 readOnly: true description: Distinct recipients who clicked at least once. example: 621 unsubscribes: type: integer minimum: 0 readOnly: true description: Distinct unsubscribe events, recorded via the list-unsubscribe header or the footer link. example: 12 open_rate: type: - number - 'null' minimum: 0 readOnly: true description: 'Distinct non-prefetched openers relative to effectively delivered recipients in the same scope, computed as `unique_opens_non_prefetched / delivery.effective_delivered`; on rows without an `effective_delivered` field (the mailbox-provider breakdowns) the denominator equals `delivery.delivered`. The numerator excludes opens auto-fetched by inbox privacy features. Opens are attributed by event time, so engagement earned by earlier deliveries can push the rate above 1. Null when the denominator is zero. ' example: 0.1683 click_rate: type: - number - 'null' minimum: 0 readOnly: true description: 'Distinct clickers relative to effectively delivered recipients in the same scope, computed as `unique_clicks / delivery.effective_delivered` (`delivery.delivered` on rows without an `effective_delivered` field). Clicks are attributed by event time, so engagement earned by earlier deliveries can push the rate above 1. Null when the denominator is zero. ' example: 0.0422 unsubscribe_rate: type: - number - 'null' minimum: 0 readOnly: true description: 'Unsubscribe events relative to effectively delivered recipients in the same scope, computed as `unsubscribes / delivery.effective_delivered` (`delivery.delivered` on rows without an `effective_delivered` field). Unsubscribes are attributed by event time, so the rate can exceed 1. Null when the denominator is zero. ' example: 0.0009 Mailbox: type: object additionalProperties: false description: 'A durable mailbox identity for an agent. A mailbox owns an email address, groups mail into threads, applies receive policy, and remembers message metadata, extracted text, and attachments for its retention tier. The body and raw MIME of each message remain available for 30 days. ' required: - id - address - display_name - default_reply_to - receive_policy - state - channel - owner - inbound_address_id - retention_tier - message_count - thread_count - size_bytes - metadata - local_part_generated - created_at - updated_at properties: id: readOnly: true $ref: '#/components/schemas/MailboxID' description: Mailbox ID. address: type: string format: email minLength: 5 readOnly: true description: The mailbox's email address. Immutable once created. example: concierge@inbox.ai display_name: type: - string - 'null' maxLength: 255 description: Display name used as the sender name on mail from this mailbox. `null` when unset. example: Acme Concierge default_reply_to: type: - string - 'null' format: email description: Default `Reply-To` address stamped on mail sent from this mailbox. `null` when unset. receive_policy: type: string minLength: 1 enum: - open - replies_only - allowlist - drop description: "Which inbound mail the mailbox accepts:\n\n- `open`: Accepts everything not blocked by a rule.\n- `replies_only`: Accepts only replies to messages this mailbox has\n sent. A reply must match a message the mailbox sent. Landing in an\n existing thread by itself does not count.\n- `allowlist`: Accepts only senders matching an allow rule. Replies to\n prior outbound mail are always admitted unless blocked.\n- `drop`: Stores nothing.\n" state: type: string minLength: 1 enum: - active - suspended readOnly: true description: Lifecycle state. `active` means the mailbox can send, receive, and expose conversations. `suspended` pauses sending, conversation reads, and events; inbound mail is retained with the `blocked` label until you resume it. channel: type: string minLength: 1 enum: - email readOnly: true description: The channel this mailbox receives on. Always `email`. owner: readOnly: true $ref: '#/components/schemas/MailboxOwner' inbound_address_id: readOnly: true $ref: '#/components/schemas/InboundAddressID' description: The underlying inbound address that receives this mailbox's mail. retention_tier: type: string minLength: 1 enum: - 30d - 90d - 1y description: How long message metadata, extracted text, and attachments are kept. Original bodies and inbound raw MIME are limited to 30 days on every tier. message_count: type: integer format: int64 readOnly: true description: Number of retained messages across all threads. thread_count: type: integer format: int64 readOnly: true description: Number of retained threads. size_bytes: type: integer format: int64 readOnly: true description: 'Stored bytes across the mailbox''s retained messages: subject, preview, extracted text, and attachment bytes. Message bodies and raw MIME expire after 30 days and do not count. Maintained with each message written or deleted, so the value is current; messages stored before the counter existed are not counted.' unread_thread_count: type: - integer - 'null' format: int64 readOnly: true description: 'Number of threads with unread messages in this mailbox, excluding trash. `null` on create/update responses. ' metadata: type: object additionalProperties: true description: Your own key/value data attached to the mailbox. Up to 2 KB. Keys starting with `__bird` are reserved. local_part_generated: readOnly: true type: boolean description: 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. created_at: type: string format: date-time minLength: 1 readOnly: true description: When the mailbox was created. updated_at: type: string format: date-time minLength: 1 readOnly: true description: When the mailbox was last updated. deleted_at: type: - string - 'null' format: date-time readOnly: true description: When the mailbox was deleted, or `null` if active. Deletion stops receiving; restore is available for 30 days unless permanent erasure has started. MailboxOwner: type: object additionalProperties: false description: The principal that owns the mailbox. Always the workspace. required: - type - id properties: type: type: string minLength: 1 enum: - workspace readOnly: true description: Owner principal type. id: readOnly: true $ref: '#/components/schemas/WorkspaceID' description: Owner principal ID. ReceiveRuleCreate: type: object additionalProperties: false description: Parameters for adding a receive rule to a mailbox. required: - action - entry properties: action: type: string minLength: 1 enum: - allow - block description: What the rule does when it matches. Block rules always win. To flip an entry's action, delete the existing rule and re-create it. entry: type: string minLength: 1 maxLength: 255 description: The sender address (`alice@example.com`) or domain (`example.com`) to match. Domains also match their subdomains. Stored lowercase. example: partner.example.com note: type: string minLength: 1 maxLength: 512 description: Your own note about why the rule exists. example: action: allow entry: partner.example.com note: Approved partner senders EmailDeliveryStats: type: object additionalProperties: false readOnly: true description: '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, each count is the sum of the per-bucket distinct counts. Event time determines attribution; send time does not. A recipient delivered on Monday counts in Monday''s row. A recipient who bounced and then succeeded on a retry can appear in both `bounced` and `delivered`. Very large counts are close estimates rather than exact tallies. These counts are successive lifecycle stages, so a recipient can appear in more than one: - `rejected`: Happens before any send attempt, from suppression, policy, or a generation failure. - `deferred`: A temporary in-flight delay that is still being retried. - `bounced`: A delivery failure, with its own hard, soft, admin, block, and undetermined sub-types. - `complained`: 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. ' required: - processed - delivered - bounced - complained - deferred - rejected - oob_bounces - effective_delivered - all_bounces - oob_rate - bounces - delivery_rate - bounce_rate - complaint_rate properties: accepted: type: integer minimum: 0 readOnly: true description: 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. example: 14820 processed: type: integer minimum: 0 readOnly: true description: Distinct recipients whose message was processed and handed off for delivery. example: 14810 delivered: type: integer minimum: 0 readOnly: true description: Distinct recipients whose message the receiving mail server accepted. example: 14720 bounced: type: integer minimum: 0 readOnly: true description: '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. ' example: 90 bounces: readOnly: true allOf: - $ref: '#/components/schemas/EmailBounceStatsWithRates' complained: type: integer minimum: 0 readOnly: true description: Distinct recipients who reported the message as spam via a feedback loop. example: 3 deferred: type: integer minimum: 0 readOnly: true description: 'Distinct recipients whose delivery the receiving server temporarily delayed and is still being retried. ' example: 14 rejected: type: integer minimum: 0 readOnly: true description: 'Distinct recipients rejected before any delivery attempt. Includes recipients on the workspace suppression list, transmissions that could not be completed, message-generation failures, and recipients refused by sending policy. The per-recipient `rejection_reason` field on `GET /v1/email/messages/{message_id}/recipients` surfaces the specific cause. ' example: 10 oob_bounces: type: integer minimum: 0 readOnly: true description: 'Out-of-band bounce events: distinct failure notifications received after the receiving server had initially confirmed delivery. The count represents deduplicated events rather than unique recipients. ' example: 2 effective_delivered: type: integer minimum: 0 readOnly: true description: Recipients who remain delivered after all bounce signals resolve, computed as `delivered - oob_bounces`. Use this as the base for engagement-rate denominators. Clamped to 0 when `oob_bounces` exceeds `delivered`. example: 14718 all_bounces: type: integer minimum: 0 readOnly: true description: Total recipients in this scope who did not receive the message, computed as `bounced + oob_bounces`. example: 92 oob_rate: type: - number - 'null' minimum: 0 maximum: 1 readOnly: true description: Share of this scope's delivery attempts that resulted in an out-of-band bounce, computed as `oob_bounces / (delivered + bounced)`. Null when there were no attempts. example: 0.00014 delivery_rate: type: - number - 'null' minimum: 0 maximum: 1 readOnly: true description: 'Share of this scope''s delivery attempts that remained delivered after all bounce signals, computed as `effective_delivered / (delivered + bounced)`. Null when there were no attempts. ' example: 0.9939 bounce_rate: type: - number - 'null' minimum: 0 maximum: 1 readOnly: true description: '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. ' example: 0.0061 complaint_rate: type: - number - 'null' minimum: 0 readOnly: true description: 'Spam complaints in this scope relative to effectively delivered recipients, computed as `complained / effective_delivered`. Complaints are attributed by event time, so a scope can record more of them than it effectively delivered, pushing the rate above 1. Null when `effective_delivered` is zero. ' example: 0.0002 WorkspaceID: type: string minLength: 1 pattern: ^ws_[0-9a-hjkmnp-tv-z]{26}$ example: ws_01krdgeqcxet5s7t44vh8rt9mg MailboxStatsResponse: type: object additionalProperties: false description: '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. ' required: - period - summary - data properties: period: $ref: '#/components/schemas/EmailStatsSeriesPeriod' summary: $ref: '#/components/schemas/MailboxStatsSummary' data: type: array readOnly: true description: One row per bucket in the period, in chronological order. Buckets with no activity are included with zero counts. items: $ref: '#/components/schemas/MailboxStatsPoint' MailboxStatsPoint: type: object additionalProperties: false readOnly: true description: '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. ' required: - bucket - sends_accepted - delivery - engagement - latency - received properties: bucket: type: string minLength: 1 readOnly: true description: The day (`YYYY-MM-DD`) or instant (RFC 3339, on the bucket boundary) this point covers, matching the period's grain. example: '2026-07-21' sends_accepted: type: integer minimum: 0 readOnly: true description: 'Distinct email messages the mailbox sent that were accepted in this bucket, counted at the message level (one per accepted send regardless of how many recipients it addresses). Every other sent-mail metric in `delivery` and `engagement` is recipient-level or event-level. ' example: 12 delivery: readOnly: true allOf: - $ref: '#/components/schemas/EmailDeliveryStats' engagement: readOnly: true allOf: - $ref: '#/components/schemas/EmailEngagementStats' latency: readOnly: true allOf: - $ref: '#/components/schemas/EmailLatencyStats' received: type: integer minimum: 0 readOnly: true description: Distinct emails the mailbox received in this bucket. example: 34 MailboxID: type: string minLength: 1 pattern: ^mbx_[0-9a-hjkmnp-tv-z]{26}$ example: mbx_01krdgeqcxet5s7t44vh8rt9mg EmailStatsSeriesPeriod: type: object additionalProperties: false description: 'The window and bucket grain the response covers, echoed from the request, plus the freshness boundary the data is current to. ' required: - from - to - grain properties: from: type: string minLength: 1 pattern: ^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2}))?$ readOnly: true description: 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. example: '2026-05-01' to: type: string minLength: 1 pattern: ^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?(Z|[+-]\d{2}:\d{2}))?$ readOnly: true description: 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. example: '2026-05-31' grain: $ref: '#/components/schemas/StatsGrain' readOnly: true data_as_of: type: - string - 'null' format: date-time readOnly: true description: '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. ' example: '2026-05-25T14:03:10Z' MailboxCreate: type: object additionalProperties: false description: Parameters for creating a mailbox. properties: local_part: type: string minLength: 1 maxLength: 64 pattern: ^[A-Za-z0-9._-]+$ description: 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. Leading, trailing, and repeated separators are not allowed. Reserved names such as `postmaster` and `abuse` are unavailable. Choosing your own local part uses one of your plan's custom-handle allowance slots; generated addresses remain available. Omit this field to generate a random local part. example: concierge domain: type: string minLength: 1 maxLength: 255 default: inbox.ai description: The domain the address lives under. Defaults to `inbox.ai`, our shared mailbox domain. Creating a mailbox claims the shared address for your organization on a first-come, first-served basis. The address remains reserved to your organization after the mailbox is deleted. You can instead use one of your own domains enabled for receiving email. example: mail.acme.com display_name: type: string minLength: 1 maxLength: 255 description: Display name used as the sender name on mail from this mailbox. example: Acme Concierge default_reply_to: type: string format: email minLength: 5 description: Default `Reply-To` address stamped on mail sent from this mailbox. receive_policy: type: string enum: - open - replies_only - allowlist - drop default: open description: "Which inbound mail the mailbox accepts:\n\n- `open`: Accepts everything not blocked by a rule.\n- `replies_only`: Accepts only replies to messages this mailbox has\n sent. A reply must match a message the mailbox sent. Landing in an\n existing thread by itself does not count.\n- `allowlist`: Accepts only senders matching an allow rule.\n- `drop`: Stores nothing.\n" retention_tier: type: string enum: - 30d - 90d - 1y default: 30d description: How long message metadata, extracted text, and attachments are kept. Original bodies and inbound raw MIME are limited to 30 days on every tier. Longer tiers require a plan that includes them. metadata: type: object additionalProperties: true description: Your own key/value data to attach to the mailbox. Up to 2 KB. Keys starting with `__bird` are reserved. example: local_part: concierge display_name: Acme Concierge receive_policy: open retention_tier: 30d EmailLatencyStats: type: object additionalProperties: false readOnly: true description: '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: - `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. - `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. - `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. Each family is reported independently. A family is omitted when no qualifying event contributed a latency measurement in the bucket. This also applies when the workspace has not recorded latency for that stage yet. The `processing` family can therefore 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. ' properties: processing: $ref: '#/components/schemas/EmailLatencyQuantiles' delivery: $ref: '#/components/schemas/EmailLatencyQuantiles' total: $ref: '#/components/schemas/EmailLatencyQuantiles' EmailLatencyQuantiles: type: object additionalProperties: false readOnly: true description: 'Approximate p50, p95, and p99 latency percentiles in milliseconds for one latency family over the bucket. All three are null when no qualifying event contributed a measurement. ' required: - p50_ms - p95_ms - p99_ms properties: p50_ms: type: - integer - 'null' minimum: 0 readOnly: true description: Median (50th percentile) latency in milliseconds. Null when no qualifying event contributed a measurement. example: 420 p95_ms: type: - integer - 'null' minimum: 0 readOnly: true description: 95th percentile latency in milliseconds. Null when no qualifying event contributed a measurement. example: 1820 p99_ms: type: - integer - 'null' minimum: 0 readOnly: true description: 99th percentile latency in milliseconds. Null when no qualifying event contributed a measurement. example: 4920 _ListEnvelope: type: object required: - next_cursor - prev_cursor - refresh_cursor properties: next_cursor: type: - string - 'null' description: Cursor for the next page. Pass back as `starting_after` to advance forward. `null` when no next page exists. example: eyJ2IjoxLCJzIjoiXCIyMDI2LTA1LTI1VDE0OjAzOjEwWlwiIiwiaSI6IjAxOTJmM2IxLTRjN2UtN2EyYi05ZDYxLThmM2E1YzJlN2I0MCJ9 prev_cursor: type: - string - 'null' description: Cursor for the previous page. Pass back as `ending_before` to step backward. `null` when no previous page exists. example: null refresh_cursor: type: - string - 'null' description: Refresh anchor, the first row of this response. Pass back as `ending_before` to fetch what precedes it in the current sort order. On a newest-first sort those are the items that have appeared since; on any other sort they are the items that sort earlier, so refreshing such a list means re-fetching it instead. Non-`null` whenever `data` is non-empty; `null` only on an empty page. Distinct from `prev_cursor`. example: eyJ2IjoxLCJzIjoiXCIyMDI2LTA1LTI1VDE2OjQyOjAxWlwiIiwiaSI6IjAxOTJmM2IxLTllMDQtN2NkMy1iODE3LTJhNmY0ZDFjOGUwOSJ9 ReceiveRuleID: type: string minLength: 1 pattern: ^erl_[0-9a-hjkmnp-tv-z]{26}$ example: erl_01krdgeqcxet5s7t44vh8rt9mg ErrorDetail: type: object additionalProperties: false required: - param - message properties: param: type: string minLength: 1 description: 'Dotted field path, such as `to[0].email`, `subject`, or `.`. When the request was rejected for a query parameter the endpoint does not declare, this carries that parameter''s name instead of a field path. ' message: type: string minLength: 1 description: What is wrong with this field. NextAction: type: object additionalProperties: false required: - kind - description properties: kind: type: string minLength: 1 x-extensible-enum: - operation - external - wait - terminal description: "What you do about this step.\n\n- `operation`: call the operation named in `operation`, then\n read again.\n- `external`: act somewhere this API does not reach, then read\n again.\n- `wait`: nothing is asked of you, so read again later.\n- `terminal`: nothing you do resolves this, so stop retrying.\n\nTolerate a value you do not recognize: show the `description` and\noffer no action.\n" description: type: string minLength: 1 description: A short, human-readable label for the step, suitable for display. operation: type: string minLength: 1 description: 'The operationId to call. Present only when `kind` is `operation`. The operation''s own schema says how to call it; this says only which one, and what to address it with. ' params: type: object additionalProperties: type: string minLength: 1 description: 'The parameters that address the operation, by name: `{"sender_id": "…"}` for an operation on `/v1/sms/senders/{sender_id}/requirements`. A parameter the operation takes in its query string is given the same way, so an operation addressed as `?subject_id=` carries `{"subject_id": "…"}`. Every parameter the call needs is here, whether its value came from the thing you were acting on or is fixed for this step, so you can make the call from this object alone. Present only when `kind` is `operation` and the operation names a subject. A request body, when the operation takes one, is described by the operation''s own schema and never appears here. ' url: type: string format: uri description: 'A URL to open. Present only when `kind` is `external`, and only when the step has one. An external step whose `description` says to go and do something with no URL to open is normal. ' ReceiveRule: type: object additionalProperties: false description: 'An allow or block entry on a mailbox, evaluated when inbound mail arrives. Matching is against the message''s envelope sender; domain entries also match subdomains. A given entry can be allow or block, never both. ' required: - id - mailbox_id - action - entry - entry_type - note - created_at properties: id: readOnly: true $ref: '#/components/schemas/ReceiveRuleID' description: Identifies this rule for deletion. There is no update operation. mailbox_id: readOnly: true $ref: '#/components/schemas/MailboxID' description: The mailbox the rule applies to. action: type: string minLength: 1 enum: - allow - block readOnly: true description: 'What the rule does when it matches. Block rules always win: over allow rules and over the reply admission on allowlist mailboxes.' entry: type: string minLength: 1 maxLength: 255 readOnly: true description: The sender address or domain the rule matches. Domains also match their subdomains. example: partner.example.com entry_type: type: string minLength: 1 enum: - address - domain readOnly: true description: Whether the entry is a full address or a domain. note: type: - string - 'null' maxLength: 512 readOnly: true description: Your own note about why the rule exists. `null` when unset. created_at: type: string format: date-time minLength: 1 readOnly: true description: When the rule was created. InboundAddressID: type: string minLength: 1 pattern: ^ina_[0-9a-hjkmnp-tv-z]{26}$ example: ina_01krdgeqcxet5s7t44vh8rt9mg Error: type: object additionalProperties: false required: - error properties: error: $ref: '#/components/schemas/ErrorBody' MailboxUpdate: type: object additionalProperties: false description: Fields to update on a mailbox. Omitted fields are unchanged. Fields set to `null` are cleared. The address and domain are immutable. properties: display_name: type: - string - 'null' maxLength: 255 description: Display name used as the sender name on mail from this mailbox. `null` clears it. default_reply_to: type: - string - 'null' format: email description: Default `Reply-To` address stamped on mail sent from this mailbox. `null` clears it. receive_policy: type: string enum: - open - replies_only - allowlist - drop description: "Which inbound mail the mailbox accepts:\n\n- `open`: Accepts everything not blocked by a rule.\n- `replies_only`: Accepts only replies to messages this mailbox has\n sent. A reply must match a message the mailbox sent. Landing in an\n existing thread by itself does not count.\n- `allowlist`: Accepts only senders matching an allow rule.\n- `drop`: Stores nothing.\n" retention_tier: type: string enum: - 30d - 90d - 1y description: How long message metadata, extracted text, and attachments are kept. Original bodies and inbound raw MIME are limited to 30 days on every tier. Longer tiers require a plan that includes them. Lowering the tier requires `confirm=true` when messages would be affected; accepted changes hide those messages immediately. Deletion waits at least ten minutes and until the retention update finishes. metadata: type: object additionalProperties: true description: Replaces the mailbox's key/value data. Up to 2 KB. Keys starting with `__bird` are reserved. example: display_name: Acme Concierge retention_tier: 30d MailboxStatsSummary: type: object additionalProperties: false readOnly: true description: '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. ' required: - sends_accepted - delivery - engagement - latency - received properties: sends_accepted: type: integer minimum: 0 readOnly: true description: Distinct email messages the mailbox sent that were accepted, counted at the message level and summed per bucket across the period. example: 231 delivery: readOnly: true allOf: - $ref: '#/components/schemas/EmailDeliveryStats' engagement: readOnly: true allOf: - $ref: '#/components/schemas/EmailEngagementStats' latency: readOnly: true allOf: - $ref: '#/components/schemas/EmailLatencyStats' received: type: integer minimum: 0 readOnly: true description: Distinct emails the mailbox received, summed per bucket across the period. example: 519 StatsGrain: type: string minLength: 1 enum: - day - hour readOnly: true description: The bucket grain of the series, either `day` or `hour`. example: day responses: InternalError: description: Internal server error content: application/json: schema: $ref: '#/components/schemas/Error' PaymentRequired: description: Insufficient balance content: application/json: schema: $ref: '#/components/schemas/Error' RateLimited: description: Rate limit exceeded headers: RateLimit: $ref: '#/components/headers/RateLimit' RateLimit-Policy: $ref: '#/components/headers/RateLimit-Policy' Retry-After: $ref: '#/components/headers/RetryAfter' content: application/json: schema: $ref: '#/components/schemas/Error' Forbidden: description: Insufficient permissions content: application/json: schema: $ref: '#/components/schemas/Error' ServiceUnavailable: description: 'The service is temporarily unavailable. If `Retry-After` is present, wait for that delay before retrying; otherwise, retry with exponential backoff. Reuse the same idempotency key and request when retrying a mutation. ' headers: Retry-After: $ref: '#/components/headers/RetryAfter' content: application/json: schema: $ref: '#/components/schemas/Error' Unprocessable: description: 'The request has invalid field values, violates a business rule, or carries a query parameter the endpoint does not declare. Field validation errors use `type: validation_error` and include the affected fields in `details`. Business-rule errors identify the failed rule in `type`. ' content: application/json: schema: $ref: '#/components/schemas/Error' NotFound: description: Resource not found content: application/json: schema: $ref: '#/components/schemas/Error' BadRequest: description: Bad request content: application/json: schema: $ref: '#/components/schemas/Error' Unauthorized: description: Authentication required content: application/json: schema: $ref: '#/components/schemas/Error' Conflict: description: Resource conflict content: application/json: schema: $ref: '#/components/schemas/Error' headers: RetryAfter: description: 'Number of seconds to wait before retrying the request. ' schema: type: integer minimum: 0 example: 35 IdempotencyReplay: description: The API includes this header when it replays the response for an earlier request that used the same `Idempotency-Key`. The API does not process the request again. schema: type: string enum: - 'true' RateLimit: description: 'Remaining capacity for the request''s rate-limit policy as an IETF Structured Field. Format: `"";r=;t=`. ' schema: type: string example: '"email_send";r=842;t=35' RateLimit-Policy: description: 'Effective quota for the request''s rate-limit policy as an IETF Structured Field. Format: `"";q=;w=`. ' schema: type: string example: '"email_send";q=1000;w=60' securitySchemes: BearerAuth: type: http scheme: bearer description: 'Pass the API key as a bearer token in the `Authorization` header. Keys use the format `bk_{region}_*`. The prefix identifies the region and selects the API endpoint. Official Bird SDKs and the CLI derive the region from the key. ' CookieAuth: type: apiKey in: cookie name: bird_session description: 'Session cookie set after signing in to the Bird dashboard. The cookie value is an opaque session token; no session data is stored in the cookie itself. ' RealtimeKey: type: apiKey in: header name: X-Realtime-Key description: 'The Realtime app key. Together with `X-Realtime-Secret`, it authenticates a request to the Realtime API in addition to the workspace credential. Both values come from the app''s credentials and must belong to the calling workspace. Official Bird SDKs accept the pair as client configuration. ' RealtimeSecret: type: apiKey in: header name: X-Realtime-Secret description: 'The Realtime app secret paired with `X-Realtime-Key`. The API returns the secret only when the key is created and does not store it. Create a new key and revoke the current key if you lose the secret. Official Bird SDKs accept the pair as client configuration. '