AI Inbx Python SDK
The official typed Python client for AI Inbx API v2. It supports synchronous and asynchronous applications, bounded retries, per-request timeouts, raw responses, idempotency keys, and signed webhook verification.
pip install aiinbx
Send an email
from aiinbx import AIInbx
with AIInbx() as client: # reads AI_INBX_API_KEY
email = client.emails.send(
{
"from_": {"name": "AI Inbx", "address": "hello@example.com"},
"to": ["ada@example.com"],
"subject": "Hello",
"text": "Sent with AI Inbx",
},
idempotency_key="welcome-ada-v1",
)
print(email["id"])
The default base URL is https://api.aiinbx.com/api/v2. Use base_url= to point
the client at a local or self-hosted API. The client retries network failures and
HTTP 408, 409, 429, and 5xx responses up to two times, honoring Retry-After.
Async
from aiinbx import AsyncAIInbx
async with AsyncAIInbx() as client:
page = await client.threads.list(limit=20)
Every sync resource has the same methods on AsyncAIInbx:
spaces:list,iter,create,retrieve,update,deleteapi_keys:list,iter,create,deleteemails:send,list,iter,retrieve,reschedule,cancelthreads:list,iter,retrieve,iter_messages,reply,forwarddomains:list,iter,create,retrieve,update,diagnostics,delete,verifymailboxes:list,iter,retrieve,connect,disconnect,syncoauth_apps:list,iter,create,retrieve,update,deletewebhook_endpoints:list,iter,create,retrieve,update,delete,rotate_secret,test,list_deliveries,iter_deliveries,retry_deliveriessuppressions:list,iter,add,retrieve,removepacing_rules:list,iter,create,retrieve,update,delete,retrieve_spread,update_spreadpacing:retrieve,releaseattachments:download,content
Every operation takes its request body as one dictionary — a TypedDict from
aiinbx.models, named after the API's schema (SendEmailRequest,
UpdateDomainRequest, …) — and its query filters as keyword arguments. The
one spelling difference from the wire is from_, since from is a Python
keyword; the SDK sends it as from. Resources, models and these method
signatures are generated from the API contract, so a change to the API is a
change here on the next release.
Reply and pagination
Replies infer the sender, recipients, subject, and RFC reply headers from the thread. Supply only the content for the common case:
reply = client.threads.reply(
"thr_123",
{"text": "Sounds good — see you Thursday."},
idempotency_key="reply-thr-123-v1",
)
# `iter()` follows cursors lazily. Async resources support `async for`.
for email in client.emails.iter(direction="inbound"):
print(email["subject"])
async for message in async_client.threads.iter_messages("thr_123"):
print(message["snippet"])
Sends, replies and forwards take an idempotency_key; every call takes a
timeout and works under with_raw_response.
Spaces
A space groups a customer's domains, mailboxes and mail. Pass space_id when
creating a domain, mailbox, suppression or pacing rule; emails and threads
inherit the space of the domain or mailbox they went through. Lists of those
take a space= filter: pass a space ID for that space, "none" for only the
workspace's own resources (space_id of None), or omit it for both the
workspace and all spaces. API keys and webhook endpoints belong to the
workspace: one key reaches every space, and one endpoint receives every space's
events, each stamped with its space_id. Spaces are optional — a workspace
that never creates one sees space_id of None everywhere.
external_id is your own id for the customer — unique per workspace, so a
second create for the same customer fails with 409 external_id_taken — and
spaces.list(external_id=...) finds the space by it.
space = client.spaces.create({"name": "Acme", "external_id": "cus_8812"})
# Later, from your side of the map:
same = client.spaces.list(external_id="cus_8812")["data"][0]
# One label under a wildcard you own (`*.mail.example.com`) is a subdomain: no DNS to publish.
client.domains.create({"name": "acme.mail.example.com", "space_id": space["id"]})
client.emails.send(
{
"from_": "Acme <hello@acme.mail.example.com>",
"to": ["ada@example.com"],
"subject": "Welcome",
"text": "Sent from Acme's own subdomain.",
}
)
Raw responses and request IDs
response = client.with_raw_response.emails.retrieve("eml_123")
print(response.status_code, response.request_id)
email = response.json()
# The most recently completed response is also exposed on the client.
print(client.last_request_id)
Non-success responses raise typed subclasses of APIStatusError. These include
status_code, request_id, response headers, and the decoded body.
Verify webhooks
Always pass the unmodified request body. The verifier signs
<unix_timestamp>.<payload> with HMAC-SHA256 and rejects payloads older than five
minutes by default.
event = client.webhooks.verify(
request_body,
request.headers["AIInbx-Signature"],
webhook_secret,
)
# `event` is the `aiinbx.WebhookEvent` union, generated from the API contract.
# Type checkers narrow `data` from the event type.
if event["type"] == "email.bounced":
for recipient in event["data"]["recipients"]:
print(recipient)
Both t=...,v1=... signatures and a bare digest plus the separate timestamp=
argument are supported. Override the replay window with tolerance= only when
necessary.
Release files for aiinbx 2.0.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| aiinbx-2.0.0.tar.gz | 88.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| aiinbx-2.0.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 141.5 kB
Release files / aiinbx-2.0.0.tar.gz
| Download URL | aiinbx-2.0.0.tar.gz |
|---|---|
| Size | 88.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
aaf5440b4ae99fd30def54a43235172de4927dca09037f79fa528fcd3ccf7a85
|
|
BLAKE2b-256 checksum How to use checksums |
4c3ae7a796dfc2b4e8c08ccc3cfb3008362a3b6f70b568e168b64f1eff07363e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency logRelease files / aiinbx-2.0.0-py3-none-any.whl
| Download URL | aiinbx-2.0.0-py3-none-any.whl |
|---|---|
| Size | 52.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
175faffd618f38e33c71e4505e471e73b2afcca53e7c6fad3080ad7ce7e21e3b
|
|
BLAKE2b-256 checksum How to use checksums |
cf367eb053bb27fe2a5c0ef2997add3bda7d2fd78a5e30601f16a0a94a833fd5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 14, 2026.
Transparency log