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. Requests time out after 60 seconds. The
client retries a 429 up to two times always, and network failures, HTTP 408 and 5xx
when a retry cannot act twice — a GET, PUT or DELETE, or a send, reply or
forward with an idempotency_key — honoring Retry-After. It never retries a 409
or other 4xx.
Async
from aiinbx import AsyncAIInbx
async with AsyncAIInbx() as client:
page = await client.threads.list(limit=20)
AsyncAIInbx mirrors AIInbx method for method. Each API resource is an
attribute of the client — client.emails, client.webhook_endpoints,
client.pacing_rules — and every endpoint page in the
API reference shows its Python call.
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)
A bad signature, a malformed header, or a timestamp outside the window raises
WebhookVerificationError. Override the replay window with tolerance= (seconds;
0 accepts only the same second) only when necessary.
Metadata
Release files for aiinbx 4.2.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 | Provenance | Actions |
|---|---|---|---|---|
| aiinbx-4.2.0.tar.gz | 111.7 kB | With provenance | Details for aiinbx-4.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| aiinbx-4.2.0-py3-none-any.whl | Python 3 | none | any | Details for aiinbx-4.2.0-py3-none-any.whl |
Total release size: 187.2 kB
Release files / aiinbx-4.2.0.tar.gz
| Download URL | aiinbx-4.2.0.tar.gz |
|---|---|
| Size | 111.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fae26deb4462439154e94acea90be5952b9770f26375843e73e7ba6bf58d1341
|
|
BLAKE2b-256 checksum How to use checksums |
dd0699257cf2330e2fe24a8cc69d802de6260478ebc9baa35eb7f4bf520f062b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 4, 2026.
Transparency logRelease files / aiinbx-4.2.0-py3-none-any.whl
| Download URL | aiinbx-4.2.0-py3-none-any.whl |
|---|---|
| Size | 75.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a4142aec894f6de36f8bd8faaf102f94ad4c30e1afd7fed2b85d81770e4b1bc3
|
|
BLAKE2b-256 checksum How to use checksums |
a6ff1ca70ca6726d24fc7dc725150022a757b6fa9e274f4b4789fe7052c7d46b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.16
|
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 Nov 4, 2026.
Transparency logSecurity for aiinbx 4.2.0
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.
Full provenance
Both files in this release have been uploaded with provenance metadata.
Attestation for aiinbx-4.2.0.tar.gz
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 Nov 4, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.