Skip to main content

Python SDK for the Inkbox API

Project description

inkbox

Python SDK for the Inkbox API — API-first communication infrastructure for AI agents (email, phone, authenticator/OTP, identities).

Install

pip install inkbox

Requires Python ≥ 3.11.

Authentication

You'll need an API key to use this SDK. Get one at console.inkbox.ai.

Quick start

import os
from inkbox import Inkbox

with Inkbox(api_key=os.environ["INKBOX_API_KEY"]) as inkbox:
    # Create an agent identity
    identity = inkbox.create_identity("support-bot")

    # Create and link new channels
    identity.create_mailbox(display_name="Support Bot")
    identity.provision_phone_number(type="toll_free")

    # Send email directly from the identity
    identity.send_email(
        to=["customer@example.com"],
        subject="Your order has shipped",
        body_text="Tracking number: 1Z999AA10123456784",
    )

    # Place an outbound call
    identity.place_call(
        to_number="+18005559999",
        client_websocket_url="wss://my-app.com/voice",
    )

    # Read inbox
    for message in identity.iter_emails():
        print(message.subject)

    # List calls
    calls = identity.list_calls()

Authentication

Argument Type Default Description
api_key str required Your ApiKey_... token
base_url str API default Override for self-hosting or testing
timeout float 30.0 Request timeout in seconds

Use with Inkbox(...) as inkbox: (recommended) or call inkbox.close() manually to clean up HTTP connections.


Identities

inkbox.create_identity() and inkbox.get_identity() return an AgentIdentity object that holds the identity's channels and exposes convenience methods scoped to those channels.

# Create and fully provision an identity
identity = inkbox.create_identity("sales-bot")
mailbox  = identity.create_mailbox(display_name="Sales Bot")      # creates + links
phone    = identity.provision_phone_number(type="toll_free")      # provisions + links

print(mailbox.email_address)
print(phone.number)

# Link an existing mailbox or phone number instead of creating new ones
identity.assign_mailbox("mailbox-uuid-here")
identity.assign_phone_number("phone-number-uuid-here")

# Get an existing identity
identity = inkbox.get_identity("sales-bot")
identity.refresh()  # re-fetch channels from API

# List all identities for your org
all_identities = inkbox.list_identities()

# Update status or handle
identity.update(status="paused")
identity.update(new_handle="sales-bot-v2")

# Unlink channels (without deleting them)
identity.unlink_mailbox()
identity.unlink_phone_number()

# Delete
identity.delete()

Mail

# Send an email (plain text and/or HTML)
sent = identity.send_email(
    to=["user@example.com"],
    subject="Hello from Inkbox",
    body_text="Hi there!",
    body_html="<p>Hi there!</p>",
    cc=["manager@example.com"],
    bcc=["archive@example.com"],
)

# Send a threaded reply
identity.send_email(
    to=["user@example.com"],
    subject=f"Re: {sent.subject}",
    body_text="Following up!",
    in_reply_to_message_id=sent.id,
)

# Send with attachments
identity.send_email(
    to=["user@example.com"],
    subject="See attached",
    body_text="Please find the file attached.",
    attachments=[{
        "filename": "report.pdf",
        "content_type": "application/pdf",
        "content_base64": "<base64-encoded-content>",
    }],
)

# Iterate inbox (paginated automatically)
for msg in identity.iter_emails():
    print(msg.subject, msg.from_address, msg.is_read)

# Filter by direction: "inbound" or "outbound"
for msg in identity.iter_emails(direction="inbound"):
    print(msg.subject)

# Iterate only unread emails
for msg in identity.iter_unread_emails():
    print(msg.subject)

# Mark messages as read
identity.mark_emails_read([msg.id for msg in identity.iter_unread_emails()])

# Get all emails in a thread (thread_id comes from msg.thread_id)
thread = identity.get_thread(msg.thread_id)
for m in thread.messages:
    print(m.subject, m.from_address)

Phone

# Place an outbound call — stream audio over WebSocket
call = identity.place_call(
    to_number="+15167251294",
    client_websocket_url="wss://your-agent.example.com/ws",
)
print(call.status, call.rate_limit.calls_remaining)

# List calls (paginated)
calls = identity.list_calls(limit=10, offset=0)
for call in calls:
    print(call.id, call.direction, call.remote_phone_number, call.status)

# Fetch transcript segments for a call
segments = identity.list_transcripts(calls[0].id)
for t in segments:
    print(f"[{t.party}] {t.text}")  # party: "local" or "remote"

# Read transcripts across all recent calls
for call in identity.list_calls(limit=10):
    segments = identity.list_transcripts(call.id)
    if not segments:
        continue
    print(f"\n--- Call {call.id} ({call.direction}) ---")
    for t in segments:
        print(f"  [{t.party:6}] {t.text}")

# Filter to only the remote party's speech
for t in identity.list_transcripts(calls[0].id):
    if t.party == "remote":
        print(t.text)

# Search transcripts across a phone number (org-level)
hits = inkbox.phone_numbers.search_transcripts(phone.id, q="refund", party="remote")
for t in hits:
    print(f"[{t.party}] {t.text}")

Authenticator

# Create an authenticator app and link it to an identity
app = identity.create_authenticator_app()

# Add an OTP account from an otpauth:// URI
account = identity.create_authenticator_account(
    otpauth_uri="otpauth://totp/Example:user@example.com?secret=EXAMPLESECRET&issuer=Example",
    display_name="My OTP Account",      # optional (max 255 chars)
    description="Login MFA for Example", # optional
)

# List all accounts in this identity's authenticator app
accounts = identity.list_authenticator_accounts()

# Get a single account
account = identity.get_authenticator_account("account-uuid")

# Update account metadata (pass None to clear a field)
identity.update_authenticator_account("account-uuid", display_name="New Label")

# Generate an OTP code
otp = identity.generate_otp("account-uuid")
print(otp.otp_code)            # e.g. "482901"
print(otp.valid_for_seconds)   # seconds until expiry (None for HOTP)
print(otp.otp_type)            # "totp" or "hotp"

# Delete an account
identity.delete_authenticator_account("account-uuid")

# Unlink authenticator app from identity
identity.unlink_authenticator_app()

# Delete the authenticator app (org-level)
inkbox.authenticator_apps.delete("app-uuid")

Org-level Mailboxes

Manage mailboxes directly without going through an identity. Access via inkbox.mailboxes.

# List all mailboxes in the organisation
mailboxes = inkbox.mailboxes.list()

# Get a specific mailbox
mailbox = inkbox.mailboxes.get("abc-xyz@inkboxmail.com")

# Create a mailbox linked to an agent identity
mailbox = inkbox.mailboxes.create(agent_handle="support-agent", display_name="Support Inbox")
print(mailbox.email_address)

# Update display name or webhook URL
inkbox.mailboxes.update(mailbox.email_address, display_name="New Name")
inkbox.mailboxes.update(mailbox.email_address, webhook_url="https://example.com/hook")
inkbox.mailboxes.update(mailbox.email_address, webhook_url=None)  # remove webhook

# Full-text search across messages in a mailbox
results = inkbox.mailboxes.search(mailbox.email_address, q="invoice", limit=20)
for msg in results:
    print(msg.subject, msg.from_address)

# Delete a mailbox
inkbox.mailboxes.delete(mailbox.email_address)

Org-level Phone Numbers

Manage phone numbers directly without going through an identity. Access via inkbox.phone_numbers.

# List all phone numbers in the organisation
numbers = inkbox.phone_numbers.list()

# Get a specific phone number by ID
number = inkbox.phone_numbers.get("phone-number-uuid")

# Provision a new number
number = inkbox.phone_numbers.provision(type="toll_free")
local  = inkbox.phone_numbers.provision(type="local", state="NY")

# Update incoming call behaviour
inkbox.phone_numbers.update(
    number.id,
    incoming_call_action="webhook",
    incoming_call_webhook_url="https://example.com/calls",
)
inkbox.phone_numbers.update(
    number.id,
    incoming_call_action="auto_accept",
    client_websocket_url="wss://example.com/ws",
)

# Full-text search across transcripts
hits = inkbox.phone_numbers.search_transcripts(number.id, q="refund", party="remote")
for t in hits:
    print(f"[{t.party}] {t.text}")

# Release a number
inkbox.phone_numbers.release(number=number.number)

Webhooks

Webhooks are configured on the mailbox or phone number resource — no separate registration step.

Mailbox webhooks

Set a URL on a mailbox to receive message.received and message.sent events.

# Set webhook
inkbox.mailboxes.update("abc@inkboxmail.com", webhook_url="https://example.com/hook")

# Remove webhook
inkbox.mailboxes.update("abc@inkboxmail.com", webhook_url=None)

Phone webhooks

Set an incoming call webhook URL and action on a phone number.

# Route incoming calls to a webhook
inkbox.phone_numbers.update(
    number.id,
    incoming_call_action="webhook",
    incoming_call_webhook_url="https://example.com/calls",
)

Signing Keys

# Create or rotate the org-level webhook signing key (plaintext returned once)
key = inkbox.create_signing_key()
print(key.signing_key)  # save this immediately

Verifying Webhook Signatures

Use verify_webhook to confirm that an incoming request was sent by Inkbox.

from inkbox import verify_webhook

# FastAPI
@app.post("/hooks/mail")
async def mail_hook(request: Request):
    raw_body = await request.body()
    if not verify_webhook(
        payload=raw_body,
        headers=request.headers,
        secret="whsec_...",
    ):
        raise HTTPException(status_code=403)
    ...

# Flask
@app.post("/hooks/mail")
def mail_hook():
    raw_body = request.get_data()
    if not verify_webhook(
        payload=raw_body,
        headers=request.headers,
        secret="whsec_...",
    ):
        abort(403)
    ...

Examples

Runnable example scripts are available in the examples/python directory:

Script What it demonstrates
register_agent_identity.py Create an identity, assign mailbox + phone number
agent_send_email.py Send an email and a threaded reply
read_agent_messages.py List messages and threads
create_agent_mailbox.py Create, update, search, and delete a mailbox
create_agent_phone_number.py Provision, update, and release a number
list_agent_phone_numbers.py List all phone numbers in the org
read_agent_calls.py List calls and print transcripts
receive_agent_email_webhook.py Register and delete a mailbox webhook
receive_agent_call_webhook.py Register, update, and delete a phone webhook
agent_authenticator_app_e2e.py Full authenticator app lifecycle (create, OTP, cleanup)

License

MIT

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

inkbox-0.1.3.tar.gz (30.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

inkbox-0.1.3-py3-none-any.whl (35.7 kB view details)

Uploaded Python 3

File details

Details for the file inkbox-0.1.3.tar.gz.

File metadata

  • Download URL: inkbox-0.1.3.tar.gz
  • Upload date:
  • Size: 30.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for inkbox-0.1.3.tar.gz
Algorithm Hash digest
SHA256 e6596fb043ed75b25f9b84ec23a0ac79f00d17904a1469573263bf16377df8f4
MD5 f6906439036184bae620806573debb76
BLAKE2b-256 e36a9c9597f888be3f4bbf5e7fb68216f0169af1f6d60cd813ea8cdc4d6a785c

See more details on using hashes here.

File details

Details for the file inkbox-0.1.3-py3-none-any.whl.

File metadata

  • Download URL: inkbox-0.1.3-py3-none-any.whl
  • Upload date:
  • Size: 35.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.13.12

File hashes

Hashes for inkbox-0.1.3-py3-none-any.whl
Algorithm Hash digest
SHA256 cb4029a02b7f2fe43c5e4b4fadbfc6cec4a02aa125129edd4645b5b7a340bd80
MD5 ed55cd6a8daa4430c42240785474a7ad
BLAKE2b-256 4d65468107f64b1c2c0b9b5d3cac5a49b35208a2d049951b6d08fe72eec1433c

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page