---
title: SDKs
description: Official TypeScript and Python clients — same resources, same idempotency and webhook verification, idiomatic in each language.
sidebar:
  label: Overview
  icon: package
---

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](/sdks/typescript)**

Dependency-free. Node 20+, Bun, Deno, and edge runtimes.

**[Python](/sdks/python)**

Sync and async clients on httpx. Python 3.10+.

## Install

```bash npm
npm install aiinbx
```

```bash pip
pip install aiinbx
```

Both read `AI_INBX_API_KEY` from the environment, so the common case needs no configuration:

```ts TypeScript
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.",
})
```

```python Python
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](/guides/spaces) |
| `apiKeys`               | `api_keys`               | [Keys and scopes](/authentication)                           |
| `emails`                | `emails`                 | [Sending](/guides/sending), [scheduling](/guides/scheduling) |
| `threads`               | `threads`                | [Conversations and replies](/guides/threads)                 |
| `domains`               | `domains`                | [Domains, DNS, diagnostics](/guides/domains)                 |
| `mailboxes`             | `mailboxes`              | [Gmail and Outlook](/guides/mailboxes)                       |
| `oauthApps`             | `oauth_apps`             | [Your own OAuth app](/guides/mailboxes#your-own-oauth-app)   |
| `webhookEndpoints`      | `webhook_endpoints`      | [Endpoints and deliveries](/webhooks)                        |
| `suppressions`          | `suppressions`           | [Suppression lists](/guides/suppressions)                    |
| `pacingRules`, `pacing` | `pacing_rules`, `pacing` | [Pacing rules and queue](/guides/pacing)                     |
| `attachments`           | `attachments`            | [Downloads and prepared text](/guides/attachments)           |

## 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_`:

```ts TypeScript
{
  from: "Ada <ada@example.com>"
}
```

```python Python
{"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](/api) 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:

1. **Send an Idempotency-Key on every send**

    Otherwise a retry after a timeout sends twice. See
    [Idempotency](/reference/conventions#idempotency).

2. **Verify webhook signatures over the raw body**

    Before parsing. See [Verifying](/webhooks/verifying#any-language).

3. **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](/reference/errors#retry-or-not).
