Documentation
Sign inGet started

Errors

Every failed request returns the same JSON envelope under a top-level error key, with an HTTP status that tells you the coarse category. This page is the wire contract; for guidance on branching, retries, and the code catalog philosophy, see Errors.
Esempio di codice
{
  "error": {
    "type": "validation_error",
    "code": "E01001",
    "name": "ValidationError",
    "message": "Request validation failed.",
    "doc_url": "https://docs.bird.com/errors/E01001",
    "request_id": "req_01krdgeqcxet5s7t44vh8rt9mg",
    "details": [
      { "param": "attachments", "message": "this field is reserved and not yet supported" },
      { "param": "scheduled_at", "message": "this field is reserved and not yet supported" }
    ]
  }
}

Envelope fields

FieldAlways presentDescription
typeYesBroad category for coarse branching — a closed enum (auth_error, validation_error, rate_limit_error, ...).
codeYesOpaque, stable identifier matching E\d{5}. Unique, never renamed, never reused — the canonical thing to match on.
nameYesHuman-readable slug (ValidationError) for log readability. Always paired with code, never a replacement for it.
messageYesHuman-readable description. Not stable — display or log it, never parse it.
doc_urlYesStable link to the documentation page for this code.
request_idYesCorrelation ID, also returned as the X-Request-Id response header. Quote it in support requests.
paramNoThe offending field, when a single field is at fault.
detailsNoPer-field validation failures as {param, message} objects, where param is a dotted path like to[0].email. Present only on validation_error responses.
vendor_codeNoVerbatim code from a downstream system (an SMTP reply code, a payment decline code) when one is worth acting on.

HTTP status mapping

Each type maps to exactly one HTTP status, so the status and the envelope never disagree.
StatustypeMeaning
400bad_request_errorThe request was malformed — unparseable body, invalid header (for example, a bad Idempotency-Key).
401auth_errorMissing, invalid, or revoked credentials. See Authentication.
402billing_errorThe request requires a payment method, balance, or plan the organization does not have.
403permission_errorAuthenticated, but not allowed — insufficient API key scope or workspace role.
404not_found_errorNo such route, or no such resource in this workspace.
409conflict_errorThe request conflicts with current state — including idempotency conflicts E01004 and E01005 (Idempotency).
412precondition_errorA precondition for the request was not met.
413payload_too_large_errorThe request body exceeds the maximum allowed size.
421misdirected_errorThe request was routed to the wrong region — use the regional host that matches your key's bk_{region}_ prefix.
422validation_errorThe body parsed but the values are invalid. details lists each failing field; reserved-but-unshipped fields such as attachments and scheduled_at on email sends also land here (E04007).
429rate_limit_errorA rate-limit group is exhausted. Retry-After gives the wait in seconds, and the RateLimit/RateLimit-Policy headers name the group and quota.
500internal_errorBird-side failure. Safe to retry with backoff — and with the same idempotency key.
501not_implemented_errorThe endpoint is declared but not yet implemented.
503service_unavailable_errorA dependency is temporarily unavailable. Retry with backoff.

Handling errors in the SDKs

Each SDK maps the envelope onto its language's native error model and carries every envelope field (type, code, message, doc_url, request_id, ...) on the error value.
Esempio di codice
import { BirdRateLimitError, BirdValidationError, BirdAPIError } from "@messagebird/sdk";

try {
  await bird.email.send({
    from: { email: "onboarding@messagebird.dev", name: "Bird" },
    to: ["delivered@messagebird.dev"],
    subject: "Hello from Bird",
    html: "<p>My first Bird email.</p>",
  });
} catch (err) {
  if (err instanceof BirdRateLimitError) console.log(`rate limited — retry in ${err.retryAfter}s`);
  else if (err instanceof BirdValidationError) console.error(err.details);
  else if (err instanceof BirdAPIError) console.error(err.code, err.requestId);
  else throw err;
}
Esempio di codice
if err != nil {
	var rle *bird.RateLimitError
	var ve *bird.ValidationError
	var ae *bird.APIError
	switch {
	case errors.As(err, &rle):
		fmt.Println("rate limited; retry after", rle.RetryAfter)
	case errors.As(err, &ve):
		for _, d := range ve.Details {
			fmt.Printf("%s: %s\n", d.Param, d.Message)
		}
	case errors.As(err, &ae):
		fmt.Printf("API error %s (status %d, request %s)\n", ae.Code, ae.StatusCode, ae.RequestID)
	default:
		log.Print(err) // transport: *bird.ConnectionError or *bird.TimeoutError
	}
}
Esempio di codice
from bird import APIStatusError, RateLimitError, ValidationError

try:
    client.email.send(
        from_={"email": "onboarding@messagebird.dev", "name": "Bird"},
        to=["delivered@messagebird.dev"],
        subject="Hello from Bird",
        text="My first Bird email.",
    )
except RateLimitError as err:
    print("rate limited; retry after", err.retry_after)
except ValidationError as err:
    print(err.status_code, err.details)
except APIStatusError as err:
    print(err.status_code, err.code, err.request_id)