Documentation
Sign inGet started

Errors

Every failed Bird API request returns the same JSON envelope, nested under a top-level error key. This is a real response to a send request with an empty body:
Codebeispiel
{
  "error": {
    "type": "validation_error",
    "code": "E01001",
    "name": "ValidationError",
    "message": "Request has 1 validation error.",
    "doc_url": "https://bird.com/docs/api/errors/E01001",
    "request_id": "req_01ky7q3hckecgv6d7jpq865532",
    "details": [{ "param": "body", "message": "missing properties 'from', 'to'" }]
  }
}
The HTTP status follows from the type: 400 for malformed requests, 401/403 for auth and permissions, 402 for billing, 404 for missing resources, 409 for conflicts, 412 for unmet preconditions, 422 for validation and business-rule failures, 429 for rate limits, 5xx for Bird-side failures. Status alone tells you the category; the envelope tells you exactly what happened.

The envelope fields

FieldRole
typeBroad category for coarse branching: validation_error, auth_error, permission_error, not_found_error, conflict_error, rate_limit_error, billing_error, internal_error, and a handful of others. A closed enum that grows rarely.
codeOpaque, stable identifier (E01001). The canonical reference: unique, never renamed, never reused. When an error is retired, its code is permanently reserved.
nameHuman-readable slug (ValidationError) for log readability. Always paired with code, never a replacement for it.
messageHuman-readable description. Not stable: wording changes without notice. Display it, log it, never parse it.
paramFor input-related errors, the offending field. Omitted when not applicable.
doc_urlStable link to the docs page for this code.
request_idAlways present, and also returned as the X-Request-Id response header. Quote it in support requests; it lets Bird trace the exact request.
detailsPer-field validation problems. Present only on validation_error responses.
remediationA human-readable next step to resolve the error. Present when a recovery is known.
nextOperations that resolve the error, in the order to try them. Present for errors with a well-defined recovery, such as unmet preconditions.
vendor_codeVerbatim code from a downstream system (an SMTP response code, a payment decline code). Present only when Bird is surfacing an external system's code you may want to act on.
unmet_gatesThe verification requirements blocking the action, each with the flow that resolves it. Present only when an action is blocked pending verification.
Branch on type for coarse handling and code for specific handling, never on message. A typical client switches on type (retry on rate_limit_error, surface validation_error to the user, page someone on internal_error) and matches individual code values only for the few errors it handles specially.
The opacity of codes is deliberate: a code like E04012 doesn't pretend to be self-documenting, so every code gets a real docs page (its doc_url) describing the exact cause and what to do about it. The full catalog lives in the error reference.

Validation failures: one code, many details

Field-level validation does not get a separate code per field-and-failure combination. Every validation failure is E01001 ValidationError with a details array listing each field-level problem as {param, message}, the way the captured send failure lists its missing properties. The message strings inside details are human-readable, not machine-stable: use param to map problems to form fields, use the message for display.

Recovery guidance: remediation and next

Errors with a known fix carry it in the envelope. This is a real response to a webhooks call made with an API key that lacks the required scope:
Codebeispiel
{
  "error": {
    "type": "permission_error",
    "code": "E02035",
    "name": "InsufficientScope",
    "message": "This request requires the \"webhooks:read\" scope, which your credential has not been granted.",
    "param": "webhooks:read",
    "doc_url": "https://bird.com/docs/api/errors/E02035",
    "request_id": "req_01ky7q4665emc9tw1pxkptaqwq",
    "remediation": "Re-authenticate with a credential that has been granted the required scope, then retry."
  }
}
remediation is a sentence for a human or an agent log; next, when present, lists the API operations that resolve the error in the order to try them (verify a domain, then retry the send). Agents and CLIs can execute next directly; interactive clients can show remediation as-is.

Handling errors well

  • Retry 429 and 5xx, nothing else by default. Honor Retry-After on rate limits (see Rate limits), use exponential backoff on 5xx, and send an Idempotency-Key so retries of mutating requests are safe.
  • Log code, name, and request_id together. The code is what you'll search the docs and your own logs for; the request ID is what support needs.
  • Tolerate new codes and types. New error codes ship regularly as products grow, and the type enum occasionally gains a value. Write your handler with a sane default branch rather than an exhaustive match.

Next steps