Every API here is available over the APIs.io API and to AI agents over MCP.
openapi: 3.2.0
info:
title: Bird Voice Destinations API
version: 1.0.0
description: 'Build communications into your applications and AI workflows with the Bird API.
Explore endpoints for email, SMS, WhatsApp, verification, and realtime messaging.
Start with the developer documentation, browse the
API reference, or connect your agent through the
Bird MCP server.
Setting a `User-Agent` header is recommended but not required. Official Bird
SDKs set it automatically (format: `bird-/`). The header is
used for operational logging and customer-support diagnostics; the API never
rejects requests that omit it.
Rate limits are advertised on every response from a rate-limited endpoint as
IETF `RateLimit` and `RateLimit-Policy` headers (Structured Fields per RFC
9651; spec draft-ietf-httpapi-ratelimit-headers-11). On 429 responses, a
`Retry-After` header in seconds is also returned. Clients should pace
themselves against the `r` (remaining) and `t` (seconds until reset) params
in the `RateLimit` header rather than only reacting to 429s.
The deprecation policy explains how
the API marks a deprecated field, query parameter, or body shape, including
the `Deprecation` response header (RFC 9745).'
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: voice-destinations
description: Manage the allowlist of destination countries your workspace may place Voice calls to. List every supported country with its enabled setting, and enable or disable countries.
paths:
/v1/voice/destinations:
get:
operationId: listVoiceDestinations
x-snippet-key: voice.destinations.list
summary: List Voice destination countries
description: Returns every country the Voice service supports, each annotated with whether your workspace has enabled calling to it, whether the platform supports calling it (`status`), and any daily spend limit you set for it with today's usage. A supported, enabled country still refuses calls once its `daily_spend_limit.remaining` reaches zero. Use this to render and manage your destination allowlist.
tags:
- voice-destinations
x-audiences:
- public
- command
security:
- BearerAuth: []
- CookieAuth: []
responses:
'200':
description: The Voice destination countries with your workspace's enabled settings.
content:
application/json:
schema:
$ref: '#/components/schemas/VoiceDestinationList'
'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'
parameters:
- $ref: '#/components/parameters/XWorkspaceId'
- $ref: '#/components/parameters/XOrganizationId'
x-surfaces:
- cli
- mcp
- sdk
patch:
operationId: updateVoiceDestinations
x-snippet-key: voice.destinations.update
summary: Update enabled Voice destination countries
description: Enables or disables specific destination countries for your workspace, and sets or removes their daily spend limits. Only the countries listed in the request change; any country you do not list keeps its current setting. Each code must be a country the Voice service supports, or the request is rejected and nothing changes; removing a daily spend limit is the exception and accepts any country code. A daily spend limit caps what your workspace spends on calls to a country each day, whether or not it is enabled.
tags:
- voice-destinations
x-audiences:
- public
- command
security:
- BearerAuth: []
- CookieAuth: []
parameters:
- $ref: '#/components/parameters/IdempotencyKey'
- $ref: '#/components/parameters/XWorkspaceId'
- $ref: '#/components/parameters/XOrganizationId'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/VoiceDestinationsUpdate'
example:
destinations:
- country_code: NL
enabled: true
- country_code: GB
enabled: false
responses:
'200':
description: The updated Voice destination countries with your workspace's enabled settings.
content:
application/json:
schema:
$ref: '#/components/schemas/VoiceDestinationList'
headers:
Idempotency-Replay:
$ref: '#/components/headers/IdempotencyReplay'
'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
- mcp
- sdk
components:
headers:
RateLimit:
description: 'Remaining capacity for the request''s rate-limit policy as an IETF Structured Field. Format: `"<policy>";r=<remaining>;t=<seconds_until_reset>`.
'
schema:
type: string
example: '"email_send";r=842;t=35'
RetryAfter:
description: 'Number of seconds to wait before retrying the request.
'
schema:
type: integer
minimum: 0
example: 35
RateLimit-Policy:
description: 'Effective quota for the request''s rate-limit policy as an IETF Structured Field. Format: `"<policy>";q=<quota>;w=<window_seconds>`.
'
schema:
type: string
example: '"email_send";q=1000;w=60'
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'
responses:
InternalError:
description: Internal server error
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'
Forbidden:
description: Insufficient permissions
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
Unauthorized:
description: Authentication required
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'
NotFound:
description: Resource not found
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'
Conflict:
description: Resource conflict
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
BadRequest:
description: Bad request
content:
application/json:
schema:
$ref: '#/components/schemas/Error'
schemas:
CurrencyCode:
type: string
minLength: 3
maxLength: 3
pattern: ^[A-Z]{3}$
description: ISO 4217 three-letter currency code.
example: EUR
DestinationSuperRegion:
type:
- string
- 'null'
minLength: 1
x-extensible-enum:
- europe
- americas
- middle_east_africa
- asia_pacific
example: europe
description: 'The continent-scale group the region rolls up into. Derived from `region`, and `null` whenever that is. Treat the set as open.
'
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.
CountryCode:
type: string
minLength: 2
maxLength: 2
pattern: ^[A-Za-z]{2}$
description: ISO 3166-1 alpha-2 country code.
example: US
Money:
type: object
additionalProperties: false
required:
- amount
- currency_code
properties:
amount:
type: string
minLength: 1
description: Decimal amount as a string, in major currency units.
example: '0.00995'
currency_code:
$ref: '#/components/schemas/CurrencyCode'
description: ISO 4217 currency code.
example: USD
Error:
type: object
additionalProperties: false
required:
- error
properties:
error:
$ref: '#/components/schemas/ErrorBody'
VoiceDestination:
type: object
additionalProperties: false
required:
- country_code
- country_name
- enabled
- status
- high_risk_destination
- daily_spend_limit
properties:
country_code:
allOf:
- $ref: '#/components/schemas/CountryCode'
readOnly: true
country_name:
type: string
minLength: 1
description: Full English country name.
example: Netherlands
readOnly: true
dial_code:
type: string
description: International dialling prefix, without the leading plus. Absent for countries that have none.
example: '31'
readOnly: true
region:
allOf:
- $ref: '#/components/schemas/DestinationRegion'
readOnly: true
super_region:
allOf:
- $ref: '#/components/schemas/DestinationSuperRegion'
readOnly: true
enabled:
type: boolean
description: Whether your workspace has enabled calling to this country.
status:
type: string
minLength: 1
x-extensible-enum:
- available
- not_supported
description: 'This country''s Voice callability at the destination level, independent of your enabled setting. `available` means we place calls there; `not_supported` means we do not.
'
readOnly: true
high_risk_destination:
type: boolean
description: Whether we treat this country as a high-risk calling destination.
readOnly: true
daily_spend_limit:
oneOf:
- $ref: '#/components/schemas/VoiceDestinationDailySpendLimit'
- type: 'null'
description: 'Your workspace''s daily spend limit for calls to this country and today''s usage toward it. It applies whether or not the country is enabled, including to verification calls. Null when you have not set one, before your organization has a wallet, or while your wallet currency cannot be read; a limit you set is still enforced then.
'
readOnly: true
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
- client_closed_request_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'
VoiceDestinationDailySpendLimitUpdate:
type: object
description: 'Sets or removes this country''s daily spend limit; omit it to leave the limit unchanged. Once today''s spend reaches the limit, new calls to the country are refused, verification calls included, whether or not it is enabled; a call already in progress is not cut off, so spend can pass the limit by what that call costs.
'
additionalProperties: false
required:
- limit
properties:
limit:
oneOf:
- $ref: '#/components/schemas/Money'
- type: 'null'
description: 'The daily spend limit for calls to this country, in your organization''s wallet currency, from zero up to the workspace''s `max_limit` in Voice settings, with at most six decimal places. Setting an amount needs an organization wallet; removing one does not. Null removes it, so only the workspace''s daily limit applies.
'
VoiceDestinationList:
type: object
additionalProperties: false
required:
- data
- total
properties:
data:
type: array
items:
$ref: '#/components/schemas/VoiceDestination'
description: The Voice destination countries, each annotated with your workspace's enabled setting.
total:
type: integer
format: int64
description: Total number of destination countries.
DestinationSetting:
type: object
additionalProperties: false
required:
- country_code
properties:
country_code:
$ref: '#/components/schemas/CountryCode'
enabled:
type: boolean
description: 'Whether to enable (`true`) or disable (`false`) this destination country. Omit it to leave the country''s enabled setting unchanged.
'
example: true
daily_spend_limit:
$ref: '#/components/schemas/VoiceDestinationDailySpendLimitUpdate'
VoiceDestinationDailySpendLimit:
type: object
additionalProperties: false
required:
- limit
- used
- remaining
- resets_at
properties:
limit:
allOf:
- $ref: '#/components/schemas/Money'
description: 'The most your workspace can spend on calls to this country each day, in your organization''s wallet currency. Calls are also held to the workspace''s own daily limit, and whichever is reached first refuses the call.
'
used:
oneOf:
- $ref: '#/components/schemas/Money'
- type: 'null'
description: 'Used toward today''s limit for this country, including calls in progress. A call counts its expected cost when it starts; the part it did not use returns when it is billed. Null when today''s usage cannot be read right now; the limit is still enforced.
'
remaining:
oneOf:
- $ref: '#/components/schemas/Money'
- type: 'null'
description: What is left of this country's limit today, never below zero. Null when today's usage cannot be read.
resets_at:
type: string
format: date-time
minLength: 1
description: When usage resets to zero, at midnight UTC.
example: '2026-10-09T00:00:00Z'
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.
'
VoiceDestinationsUpdate:
type: object
additionalProperties: false
required:
- destinations
properties:
destinations:
type: array
items:
$ref: '#/components/schemas/DestinationSetting'
description: 'The destination countries to change. Only the countries listed here change, and only the fields you send; anything else keeps its current setting. A country listed more than once takes its last `enabled`, but may set or remove `daily_spend_limit` only once. A limit can be set only on a country the Voice service supports; removing one accepts any country code. Otherwise the request is rejected and nothing changes.
'
example:
- country_code: NL
enabled: true
- country_code: GB
enabled: false
daily_spend_limit:
limit:
amount: '25.00'
currency_code: EUR
DestinationRegion:
type:
- string
- 'null'
minLength: 1
x-extensible-enum:
- western_europe
- nordics_baltics
- southern_europe
- central_eastern_europe
- north_america
- latin_america_caribbean
- middle_east_north_africa
- sub_saharan_africa
- central_asia_caucasus
- south_asia
- south_east_asia
- east_asia
- oceania
example: western_europe
description: 'The commercial region this country belongs to, for grouping a destination list the way it is bought rather than alphabetically. `null` for a country we have not assigned yet. Bird defines these regions independently of ISO and UN M49. A country can move between them, so treat the set as open.
'
parameters:
XWorkspaceId:
name: X-Workspace-Id
in: header
required: false
description: Workspace context for the request. Required for dashboard authentication and master keys. Workspace keys and access tokens already identify their workspace; send that workspace or omit the header. A different one is rejected.
schema:
type: string
pattern: ^ws_[0-9a-hjkmnp-tv-z]{26}$
XOrganizationId:
name: X-Organization-Id
in: header
required: false
description: Organization context for the request. Required for dashboard authentication. An API key or access token carries its own organization, so send either that organization or no header at all; a different one is rejected.
schema:
type: string
pattern: ^org_[0-9a-hjkmnp-tv-z]{26}$
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 unscoped 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 `<event-type>/<entity-id>` (for example `welcome-user/usr_abc123`).\n"
schema:
type: string
maxLength: 255
securitySchemes:
BearerAuth:
type: http
scheme: bearer
description: 'Pass the API key as a bearer token in the `Authorization` header. Workspace
keys use `bk_{region}_*`; organization master keys use `bm_{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.
'