SDKs
Official TypeScript and Python clients — same resources, same idempotency and webhook verification, idiomatic in each language.
Two official clients. They cover the same API v2 surface with the same resource names, and each is written the way its language expects rather than being a thin translation of the other.
TypeScript
Dependency-free. Node 20+, Bun, Deno, and edge runtimes.
Python
Sync and async clients on httpx. Python 3.10+.
Install
npm install aiinbxpip install aiinbxBoth read AI_INBX_API_KEY from the environment, so the common case needs no configuration:
import AIInbx from "aiinbx"
const aiinbx = new AIInbx()
const email = await aiinbx.emails.send({
from: "Ada <ada@example.com>",
to: "grace@example.com",
subject: "Hello",
text: "Sent with AI Inbx.",
})from aiinbx import AIInbx
with AIInbx() as client:
email = client.emails.send(
{
"from_": "Ada <ada@example.com>",
"to": ["grace@example.com"],
"subject": "Hello",
"text": "Sent with AI Inbx.",
}
)What both give you
| Behaviour | |
|---|---|
| Retries | Network errors and HTTP 408, 409, 429, and 5xx, twice by default with bounded exponential backoff. Retry-After is honored. |
| Idempotency | A per-request key on sends and replies. |
| Pagination | Await a call for one page, or iterate for every page with your filters preserved. |
| Request IDs | Reachable without unwrapping the response. |
| Typed errors | A subclass per status, carrying status, code, request_id, headers, and the parsed body. |
| Webhook verification | Timing-safe HMAC checking with a replay window, and a discriminated event union. |
| Types | Full TypeScript types; py.typed and typed dicts for Python. |
Resources
| TypeScript | Python | Covers |
|---|---|---|
spaces |
spaces |
Customer spaces |
apiKeys |
api_keys |
Keys and scopes |
emails |
emails |
Sending, scheduling |
threads |
threads |
Conversations and replies |
domains |
domains |
Domains, DNS, diagnostics |
mailboxes |
mailboxes |
Gmail and Outlook |
oauthApps |
oauth_apps |
Your own OAuth app |
webhookEndpoints |
webhook_endpoints |
Endpoints and deliveries |
suppressions |
suppressions |
Suppression lists |
pacingRules, pacing |
pacing_rules, pacing |
Pacing rules and queue |
attachments |
attachments |
Downloads and prepared text |
Naming
Two differences to know before you copy a snippet between them.
from is a reserved word in Python, so the Python client uses from_:
{
from: "Ada <ada@example.com>"
}{"from_": "Ada <ada@example.com>"}Everything else keeps the wire name. Request and response fields are snake_case in both — thread_id, scheduled_at, suppression_key — because they’re the API’s names, not the language’s. Only the client’s own options follow each language’s convention: baseURL / base_url, maxRetries / max_retries, idempotencyKey / idempotency_key.
Without an SDK
The API is plain HTTP with bearer auth and JSON bodies. Curl examples run throughout the guides, and the API reference has a request builder per endpoint with generated curl, JavaScript, and Python samples.
Three things to get right if you’re writing your own client:
Send an Idempotency-Key on every send
Otherwise a retry after a timeout sends twice. See Idempotency.
Verify webhook signatures over the raw body
Before parsing. See Verifying.
Retry 429 and 5xx with backoff, and nothing else
Handle 408 and network timeouts as uncertain outcomes; retry sends only with the same idempotency key and payload. Inspect other 4xx errors before retrying. See
Errors.