Official SDKs for the Inkbox API — API-first communication infrastructure for AI agents (identities, email, phone).
| Package | Language | Install |
|---|---|---|
inkbox | Python ≥ 3.11 | pip install inkbox |
@inkbox/sdk | TypeScript / Node ≥ 18 | npm install @inkbox/sdk |
All SDK calls require an API key. You can obtain one from the Inkbox Console.
Agent identities are the central concept — a named identity (e.g. "sales-agent") that owns a mailbox and/or phone number. Use Inkbox as the org-level entry point to create and retrieve identities.
frominkboximportInkboxwithInkbox(api_key="ApiKey_...") asinkbox:
# Create an identity — returns an AgentIdentity objectidentity=inkbox.create_identity("sales-agent")
# Create and link new channelsmailbox=identity.create_mailbox(display_name="Sales Agent")
phone=identity.provision_phone_number(type="toll_free")
print(mailbox.email_address)
print(phone.number)
# Link an existing mailbox or phone number instead of creating new onesidentity.assign_mailbox("mailbox-uuid-here")
identity.assign_phone_number("phone-number-uuid-here")
# Unlink channels without deleting themidentity.unlink_mailbox()
identity.unlink_phone_number()
# List, get, update, delete, refreshidentities=inkbox.list_identities()
identity=inkbox.get_identity("sales-agent")
identity.update(status="paused") # or new_handle="new-name"identity.refresh() # re-fetch from API, updates cached channelsidentity.delete() # soft-delete; unlinks channelsimport{Inkbox}from"@inkbox/sdk";constinkbox=newInkbox({apiKey: "ApiKey_..."});// Create an identity — returns an AgentIdentity objectconstidentity=awaitinkbox.createIdentity("sales-agent");// Create and link new channelsconstmailbox=awaitidentity.createMailbox({displayName: "Sales Agent"});constphone=awaitidentity.provisionPhoneNumber({type: "toll_free"});console.log(mailbox.emailAddress);console.log(phone.number);// Link an existing mailbox or phone number instead of creating new onesawaitidentity.assignMailbox("mailbox-uuid-here");awaitidentity.assignPhoneNumber("phone-number-uuid-here");// Unlink channels without deleting themawaitidentity.unlinkMailbox();awaitidentity.unlinkPhoneNumber();// List, get, update, delete, refreshconstidentities=awaitinkbox.listIdentities();consti=awaitinkbox.getIdentity("sales-agent");awaiti.update({status: "paused"});// or newHandle: "new-name"awaiti.refresh();// re-fetch from API, updates cached channelsawaiti.delete();// soft-delete; unlinks channelsfrominkboximportInkboxwithInkbox(api_key="ApiKey_...") asinkbox:
identity=inkbox.get_identity("sales-agent")
# 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 replyidentity.send_email(
to=["user@example.com"],
subject=f"Re: {sent.subject}",
body_text="Following up!",
in_reply_to_message_id=sent.id,
)
# Send with attachmentsidentity.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 over all messages (pagination handled automatically)formsginidentity.iter_emails():
print(msg.subject, msg.from_address, msg.is_read)
# Filter by direction: "inbound" or "outbound"formsginidentity.iter_emails(direction="inbound"):
print(msg.subject)
# Iterate only unread messagesformsginidentity.iter_unread_emails():
print(msg.subject)
# Mark messages as readunread_ids= [msg.idformsginidentity.iter_unread_emails()]
identity.mark_emails_read(unread_ids)
# Get a full thread (all messages, oldest-first)formsginidentity.iter_emails():
thread=identity.get_thread(msg.thread_id)
forminthread.messages:
print(f"[{m.from_address}] {m.subject}")
breakimport{Inkbox}from"@inkbox/sdk";constinkbox=newInkbox({apiKey: "ApiKey_..."});constidentity=awaitinkbox.getIdentity("sales-agent");// Send an email (plain text and/or HTML)constsent=awaitidentity.sendEmail({to: ["user@example.com"],subject: "Hello from Inkbox",bodyText: "Hi there!",bodyHtml: "<p>Hi there!</p>",cc: ["manager@example.com"],bcc: ["archive@example.com"],});// Send a threaded replyawaitidentity.sendEmail({to: ["user@example.com"],subject: `Re: ${sent.subject}`,bodyText: "Following up!",inReplyToMessageId: sent.id,});// Send with attachmentsawaitidentity.sendEmail({to: ["user@example.com"],subject: "See attached",bodyText: "Please find the file attached.",attachments: [{filename: "report.pdf",contentType: "application/pdf",contentBase64: "<base64-encoded-content>",}],});// Iterate over all messages (pagination handled automatically)forawait(constmsgofidentity.iterEmails()){console.log(msg.subject,msg.fromAddress,msg.isRead);}// Filter by direction: "inbound" or "outbound"forawait(constmsgofidentity.iterEmails({direction: "inbound"})){console.log(msg.subject);}// Iterate only unread messagesforawait(constmsgofidentity.iterUnreadEmails()){console.log(msg.subject);}// Mark messages as readconstunreadIds: string[]=[];forawait(constmsgofidentity.iterUnreadEmails())unreadIds.push(msg.id);awaitidentity.markEmailsRead(unreadIds);// Get a full thread (all messages, oldest-first)forawait(constmsgofidentity.iterEmails()){constthread=awaitidentity.getThread(msg.threadId);for(constmofthread.messages){console.log(`[${m.fromAddress}] ${m.subject}`);}break;}frominkboximportInkboxwithInkbox(api_key="ApiKey_...") asinkbox:
identity=inkbox.get_identity("sales-agent")
# Place an outbound call — stream audio over WebSocketcall=identity.place_call(
to_number="+15167251294",
client_websocket_url="wss://your-agent.example.com/ws",
)
print(call.status)
print(call.rate_limit.calls_remaining)
# Or receive call events via webhook insteadcall=identity.place_call(
to_number="+15167251294",
webhook_url="https://your-agent.example.com/call-events",
)
# List calls (paginated)calls=identity.list_calls(limit=10, offset=0)
forcallincalls:
print(call.id, call.direction, call.remote_phone_number, call.status)
# Fetch transcript segments for a callsegments=identity.list_transcripts(calls[0].id)
fortinsegments:
print(f"[{t.party}] {t.text}") # party: "local" or "remote"import{Inkbox}from"@inkbox/sdk";constinkbox=newInkbox({apiKey: "ApiKey_..."});constidentity=awaitinkbox.getIdentity("sales-agent");// Place an outbound call — stream audio over WebSocketconstcall=awaitidentity.placeCall({toNumber: "+15167251294",clientWebsocketUrl: "wss://your-agent.example.com/ws",});console.log(call.status);console.log(call.rateLimit.callsRemaining);// Or receive call events via webhook insteadconstcall2=awaitidentity.placeCall({toNumber: "+15167251294",webhookUrl: "https://your-agent.example.com/call-events",});// List calls (paginated)constcalls=awaitidentity.listCalls({limit: 10,offset: 0});for(constcofcalls){console.log(c.id,c.direction,c.remotePhoneNumber,c.status);}// Fetch transcript segments for a callconstsegments=awaitidentity.listTranscripts(calls[0].id);for(consttofsegments){console.log(`[${t.party}] ${t.text}`);// party: "local" or "remote"}Manage mailboxes directly without going through an identity. Access via inkbox.mailboxes.
frominkboximportInkboxwithInkbox(api_key="ApiKey_...") asinkbox:
# List all mailboxes in the organisationmailboxes=inkbox.mailboxes.list()
# Get a specific mailboxmailbox=inkbox.mailboxes.get("abc-xyz@inkboxmail.com")
# Create a mailbox linked to an agent identitymailbox=inkbox.mailboxes.create(agent_handle="support-agent", display_name="Support Inbox")
print(mailbox.email_address)
# Update display name or webhook URLinkbox.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 mailboxresults=inkbox.mailboxes.search(mailbox.email_address, q="invoice", limit=20)
formsginresults:
print(msg.subject, msg.from_address)
# Delete a mailboxinkbox.mailboxes.delete(mailbox.email_address)import{Inkbox}from"@inkbox/sdk";constinkbox=newInkbox({apiKey: "ApiKey_..."});// List all mailboxes in the organisationconstmailboxes=awaitinkbox.mailboxes.list();// Get a specific mailboxconstmailbox=awaitinkbox.mailboxes.get("abc-xyz@inkboxmail.com");// Create a mailbox linked to an agent identityconstmb=awaitinkbox.mailboxes.create({agentHandle: "support-agent",displayName: "Support Inbox"});console.log(mb.emailAddress);// Update display name or webhook URLawaitinkbox.mailboxes.update(mb.emailAddress,{displayName: "New Name"});awaitinkbox.mailboxes.update(mb.emailAddress,{webhookUrl: "https://example.com/hook"});awaitinkbox.mailboxes.update(mb.emailAddress,{webhookUrl: null});// remove webhook// Full-text search across messages in a mailboxconstresults=awaitinkbox.mailboxes.search(mb.emailAddress,{q: "invoice",limit: 20});for(constmsgofresults){console.log(msg.subject,msg.fromAddress);}// Delete a mailboxawaitinkbox.mailboxes.delete(mb.emailAddress);Manage phone numbers directly without going through an identity. Access via inkbox.phone_numbers (Python) / inkbox.phoneNumbers (TypeScript).
frominkboximportInkboxwithInkbox(api_key="ApiKey_...") asinkbox:
# List all phone numbers in the organisationnumbers=inkbox.phone_numbers.list()
# Get a specific phone number by IDnumber=inkbox.phone_numbers.get("phone-number-uuid")
# Provision a new numbernumber=inkbox.phone_numbers.provision(type="toll_free")
local=inkbox.phone_numbers.provision(type="local", state="NY")
# Update incoming call behaviourinkbox.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 transcriptshits=inkbox.phone_numbers.search_transcripts(number.id, q="refund", party="remote")
fortinhits:
print(f"[{t.party}] {t.text}")
# Release a numberinkbox.phone_numbers.release(number=number.number)import{Inkbox}from"@inkbox/sdk";constinkbox=newInkbox({apiKey: "ApiKey_..."});// List all phone numbers in the organisationconstnumbers=awaitinkbox.phoneNumbers.list();// Get a specific phone number by IDconstnumber=awaitinkbox.phoneNumbers.get("phone-number-uuid");// Provision a new numberconstnum=awaitinkbox.phoneNumbers.provision({type: "toll_free"});constlocal=awaitinkbox.phoneNumbers.provision({type: "local",state: "NY"});// Update incoming call behaviourawaitinkbox.phoneNumbers.update(num.id,{incomingCallAction: "webhook",incomingCallWebhookUrl: "https://example.com/calls",});awaitinkbox.phoneNumbers.update(num.id,{incomingCallAction: "auto_accept",clientWebsocketUrl: "wss://example.com/ws",});// Full-text search across transcriptsconsthits=awaitinkbox.phoneNumbers.searchTranscripts(num.id,{q: "refund",party: "remote"});for(consttofhits){console.log(`[${t.party}] ${t.text}`);}// Release a numberawaitinkbox.phoneNumbers.release({number: num.number});Webhooks are configured on the mailbox or phone number resource — no separate registration step.
Set a URL on a mailbox to receive message.received and message.sent events.
# Pythoninkbox.mailboxes.update("abc@inkboxmail.com", webhook_url="https://example.com/hook")
# Remove:inkbox.mailboxes.update("abc@inkboxmail.com", webhook_url=None)// TypeScriptawaitinkbox.mailboxes.update("abc@inkboxmail.com",{webhookUrl: "https://example.com/hook"});// Remove:awaitinkbox.mailboxes.update("abc@inkboxmail.com",{webhookUrl: null});Set an incoming call webhook URL and action on a phone number.
# Python — route incoming calls to a webhookinkbox.phone_numbers.update(
number.id,
incoming_call_action="webhook",
incoming_call_webhook_url="https://example.com/calls",
)// TypeScript — route incoming calls to a webhookawaitinkbox.phoneNumbers.update(number.id,{incomingCallAction: "webhook",incomingCallWebhookUrl: "https://example.com/calls",});You can also supply a per-call webhook URL when placing a call:
# Pythonidentity.place_call(to_number="+15005550006", webhook_url="https://example.com/call-events")// TypeScriptawaitidentity.placeCall({toNumber: "+15005550006",webhookUrl: "https://example.com/call-events"});Org-level webhook signing keys are managed through the Inkbox client.
frominkboximportInkboxwithInkbox(api_key="ApiKey_...") asinkbox:
# Create or rotate the org-level signing key (plaintext returned once)key=inkbox.create_signing_key()
print(key.signing_key) # save thisimport{Inkbox}from"@inkbox/sdk";constinkbox=newInkbox({apiKey: "ApiKey_..."});// Create or rotate the org-level signing key (plaintext returned once)constkey=awaitinkbox.createSigningKey();console.log(key.signingKey);// save thisUse verify_webhook / verifyWebhook to confirm that an incoming request was sent by Inkbox. The function checks the HMAC-SHA256 signature over {request_id}.{timestamp}.{body}.
frominkboximportverify_webhookis_valid=verify_webhook(
payload=raw_body, # bytessignature=request.headers["X-Inkbox-Signature"],
request_id=request.headers["X-Inkbox-Request-ID"],
timestamp=request.headers["X-Inkbox-Timestamp"],
secret="whsec_...", # from create_signing_key()
)import{verifyWebhook}from"@inkbox/sdk";constvalid=verifyWebhook({payload: req.body,// Buffer or stringsignature: req.headers["x-inkbox-signature"]asstring,requestId: req.headers["x-inkbox-request-id"]asstring,timestamp: req.headers["x-inkbox-timestamp"]asstring,secret: "whsec_...",// from createSigningKey()});MIT