Authentication
Bearer API keys, the three scopes and what each one reaches, and how keys are rotated and deleted.
Every request carries an API key as a bearer token:
curl https://api.aiinbx.com/api/v2/threads \
-H "Authorization: Bearer $AI_INBX_API_KEY"
Both SDKs read AI_INBX_API_KEY from the environment, so the common case needs no argument:
import AIInbx from "aiinbx"
const aiinbx = new AIInbx() // or new AIInbx({ apiKey: "..." })from aiinbx import AIInbx
with AIInbx() as client: # or AIInbx(api_key="...")
...A key belongs to one workspace, reaches every space in it, and can never cross into another workspace. Keys are for your servers; a customer who needs the API goes through your product, never through AI Inbx directly.
Base URL
https://api.aiinbx.com/api/v2
Both SDKs default to it. Override with baseURL (TypeScript) or base_url (Python) when you’re pointing at a local instance.
Scopes
A key is created with one of three scopes. full satisfies every requirement; the other two are deliberate narrowings for keys that live somewhere you’d rather not put a full key.
fullscope
Everything. Required for anything that changes configuration — keys, domains, mailboxes, OAuth apps, webhook endpoints, suppressions, and pacing rules.
scopesending?scope
Reads, plus sending: send an email, reply or forward a thread, reschedule, and cancel. Cannot change configuration.
scoperead?scope
Reads only: list and retrieve emails, threads, domains, mailboxes, deliveries, suppressions, and pacing state.
scopeConcretely:
| Operation | read |
sending |
full |
|---|---|---|---|
| List and retrieve emails, threads, attachments | ✓ | ✓ | ✓ |
| Read domains, mailboxes, webhook endpoints and deliveries, suppressions, pacing | ✓ | ✓ | ✓ |
| Send an email, reply on a thread | ✓ | ✓ | |
| Reschedule or cancel a scheduled email | ✓ | ✓ | |
| Create, update, delete domains, mailboxes, OAuth apps, webhook endpoints | ✓ | ||
| Manage suppressions and pacing rules | ✓ | ||
| Create and delete API keys | ✓ |
Managing keys
Keys are created in the console or through the API with a full key. The plaintext key is returned once, on the create call:
const created = await aiinbx.apiKeys.create({
name: "background worker",
scope: "sending",
})
console.log(created.key) // the only time you see itcreated = client.api_keys.create(name="background worker", scope="sending")
print(created["key"]) # the only time you see itcurl https://api.aiinbx.com/api/v2/api-keys \
-H "Authorization: Bearer $AI_INBX_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "name": "background worker", "scope": "sending" }'Afterwards a key lists as metadata only — its prefix, scope, created_at, and last_used_at. last_used_at is the field to check before deleting a key you’re no longer sure about.
Rotating
Rotate a key by creating a replacement, deploying it, and deleting the old key after the cutover.
Create the replacement
Same scope, a name that says what it replaces.
Deploy it
Roll it out everywhere the old key was configured.
Watch last_used_at
List keys until the old one stops advancing.
Delete the old key
apiKeys.delete(id) — takes effect immediately.
Deletion is permanent. The key disappears from the list and authenticates nothing.
Request IDs
Every response carries X-Request-ID, and every error body repeats it as request_id. If you send your own X-Request-ID — up to 128 characters of A-Za-z0-9._:- — it’s echoed back instead of a generated one, which is what you want when you already have a trace ID to correlate against. See Conventions.