Documentation
Sign inGet started

SDK concepts

The TypeScript, Go, Python, and PHP SDKs follow one design. Each has a generated base with types and a low-level client produced from Bird's OpenAPI specification. A hand-written layer manages the request lifecycle and exposes the curated surface. This page covers their shared behavior. The per-language pages cover idiomatic details.

Auto-idempotency

Every mutation (POST, PUT, PATCH, DELETE) gets an auto-generated Idempotency-Key header. The key is generated once per logical call and reused across every retry attempt. This prevents a retried write from applying twice. If a send times out after the server processes it, the retry receives the stored response. Pass your own key (per-call idempotencyKey / option.WithIdempotencyKey / idempotency_key) when the logical operation spans more than one SDK call, such as an application retry loop around the SDK. See Idempotency for the server-side protocol.

Safe retries

Retries are on by default (maxRetries: 2 in every SDK). The client retries transient failures, including network errors, per-attempt timeouts, 429 responses, and retryable 5xx responses. It uses jittered exponential backoff and honors the server's Retry-After header. Deterministic failures (401, 404, 422, and other 4xx responses) are never retried. Reusing the idempotency key makes mutation retries safe. The timeout applies to each attempt (60 seconds by default), so a call with retries can take longer. PHP uses the timeout enforced by the injected HTTP client because PSR-18 has no portable per-request timeout.

Pagination

List endpoints are cursor-paginated. Every SDK supports native iteration, which fetches successive pages automatically. For manual cursor control, use the single-page accessor. Each page includes data and next_cursor; pass the cursor back as starting_after to advance.
for await (const message of bird.email.list({ status: "bounced" })) {
  console.log(message.id);
}
const page = await bird.email.list({ limit: 50 }); // page.data, page.next_cursor
See the pagination reference for cursors, limit, and include_total.

Region inference

Bird API keys encode their region: bk_{region}_{token}. The SDK reads the prefix and routes to https://{region}.platform.bird.com automatically. A region option overrides the inferred region. An explicit baseUrl (option.WithBaseURL / base_url) takes precedence over both and supports local development or self-hosted deployments. Construction fails when the key does not match the bk_{region}_ format and no override is set.

Per-call options vs construction-only config

Configuration has two tiers. Identity and transport settings are construction-only: the API key, base URL or region, and the HTTP client or fetch implementation. Lifecycle settings can be set as construction defaults and overridden per call: timeout, maxRetries, the idempotency key, and extra headers. TypeScript, Python, and PHP use a trailing options object; Go uses variadic option.With… options. SDK-owned headers (Authorization, User-Agent, Idempotency-Key) take precedence over caller-supplied headers. Channel defaults, such as a default email from, follow the same pattern.

Webhook verification

Each SDK provides one verification entry point: webhooks.unwrap(rawBody, headers). It implements Standard Webhooks with HMAC-SHA256 over the raw payload and your endpoint's signing secret. It accepts v1-tagged signature entries, rejects timestamps outside a 5-minute tolerance window, and compares signatures in constant time. Pass the raw request body bytes exactly as received. Parsing and re-serializing the JSON changes the bytes and invalidates the signature.
On success, unwrap returns a typed event discriminated on type, such as email.delivered or email.bounced. Unknown event types still verify and decode, so handle them in your default branch. Verification failure is a distinct error (BirdWebhookVerificationError / *WebhookVerificationError / WebhookVerificationError); respond with 400. See Webhooks for endpoint setup and the event catalog.

Next steps