aethexDocs

Python SDK

Official Python SDK for the AethexAI Voice API. Create and manage production voice agents, trigger real phone calls, synthesize speech, transcribe audio, and run realtime conversations from Python.

Installation

The SDK ships as the aethexai package on PyPI and requires Python 3.10+. Install it with pip or uv using the commands below. The realtime extra additionally pulls aiortc and PyAV; PyAV ships prebuilt wheels for common platforms, but unusual platforms may need FFmpeg development headers before PyAV can build from source.

bash
pip install aethexai

Quick Setup

Import AethexAI and initialise it with your API key. The SDK uses API-key authentication for voice API calls; developer JWT login is only for dashboard auth. Pass api_key explicitly or set AETHEX_API_KEY.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

# Verify the connection by listing available voices.
voices = client.list_voices(limit=5)
for voice in voices:
    print(voice.id, voice.name)

Context Manager

AethexAI and AsyncAethexAI support context managers so HTTP connections are closed when the block exits.

python
from aethexai import AethexAI

with AethexAI(api_key="ae_live_...") as client:
    page = client.list_agents(limit=20)
    print(page.data)

Kora

Kora is the voice-focused client: agents, outbound calls, voices, TTS, transcription, and conversation history without the account-management surface. trigger_call requires a from_number that is registered to your tenant for outbound calling — the gateway rejects an omitted from_number with HTTP 422 (unless the server sets TWILIO_PHONE_NUMBER as a fallback).

python
from aethexai import Kora

kora = Kora(base_url="https://api.aethexai.com", api_key="ae_live_...")

voices = kora.list_voices(limit=1)
agent = kora.create_agent(
    name="Support Agent",
    system_prompt="You are a helpful customer support agent.",
    first_message="Hi there! How can I help you today?",
    voice_id=voices[0].id,
    language="english",
)

with open("recording.wav", "rb") as f:
    result = kora.transcribe(f.read(), language="english")
print(result.text)

Agents

Create, list, retrieve, update, duplicate, and delete voice agents. All create/update methods accept keyword arguments that map to the API request body. Paginated endpoints return objects with .data, .total, .offset, and .limit; compute end-of-results as page.offset + len(page.data) >= page.total. The list_/create_/update_/duplicate_/trigger_call write methods currently surface the raw JSON dict, so use bracket access (e.g. agent["id"]); single-resource reads such as get_agent and the items in list_voices return typed attrs models, so attribute access works (agent.id, voice.id).

List Agents

List all agents in your tenant. Returns a paginated result with .data, .total, .offset, and .limit.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

page = client.list_agents(limit=20, offset=0)
for agent in page.data:
    print(agent.id, agent.name)

Create Agent

Create a new voice agent. Write methods return the underlying JSON dict — access fields with ["id"].

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")
voices = client.list_voices(language="english", limit=1)

agent = client.create_agent(
    name="Support Bot",
    system_prompt="You are a helpful customer support agent.",
    first_message="Hi there! How can I help you today?",
    voice_id=voices[0].id,
    language="english",
)
print(agent.id)

Get Agent

Retrieve a single agent by ID. Returns a typed AgentResponse — use attribute access (agent.id, agent.name).

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

agent = client.get_agent("8a1b2c3d-4e5f-6789-abcd-ef0123456789")
print(agent.id, agent.name, agent.voice_id)

Update Agent

Update an existing agent. Pass only the fields you want to change.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.update_agent(
    "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    name="Updated Support Bot",
    first_message="Welcome back!",
)

Delete Agent

Permanently delete an agent by ID.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.delete_agent("8a1b2c3d-4e5f-6789-abcd-ef0123456789")

Duplicate Agent

Create an exact copy of an existing agent. Returns the new agent dict.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

clone = client.duplicate_agent("8a1b2c3d-4e5f-6789-abcd-ef0123456789")
print(clone.id)

Add Agent Tool

Attach a function tool to an agent. parameters is a full JSON Schema object sent to the LLM. endpoint_url is called by the voice pipeline when the LLM invokes the tool.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

tool = client.add_agent_tool(
    "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    name="lookup_order",
    description="Look up an order by ID",
    parameters={
        "type": "object",
        "properties": {"order_id": {"type": "string"}},
        "required": ["order_id"],
    },
    endpoint_url="https://api.example.com/orders",
)
print(tool["id"])

List Agent Tools

List all tools attached to an agent.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

tools = client.list_agent_tools("8a1b2c3d-4e5f-6789-abcd-ef0123456789")
for tool in tools:
    print(tool["id"], tool["name"])

Update Agent Tool

Update a tool attached to an agent. Pass only the fields you want to change.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.update_agent_tool(
    "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    "3c2d1e0f-9a8b-7c6d-5e4f-3a2b1c0d9e8f",
    description="Look up an order by its internal ID",
)

Delete Agent Tool

Remove a tool from an agent.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.delete_agent_tool(
    "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    "3c2d1e0f-9a8b-7c6d-5e4f-3a2b1c0d9e8f",
)

Upload Knowledge Document

Upload a document directly to the agent's knowledge base as multipart/form-data.

python
from aethexai import AethexAI
from aethexai._generated.types import File
from aethexai._generated.models import (
    BodyUploadKnowledgeDocApiV1AgentsAgentIdKnowledgeBasePost as UploadBody,
)

client = AethexAI(api_key="ae_live_...")

with open("faq.pdf", "rb") as f:
    body = UploadBody(
        file=File(payload=f, file_name="faq.pdf", mime_type="application/pdf"),
        filename="faq.pdf",
    )
    doc = client.upload_knowledge_doc(
        "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
        body=body,
    )
print(doc["id"])

Upload Knowledge Document by Upload

Upload a knowledge document via a presigned URL. Call presign_upload to get a signed PUT URL, PUT the file bytes, then register the upload with this method.

python
from aethexai import AethexAI
import httpx

client = AethexAI(api_key="ae_live_...")

upload = client.presign_upload(kind="doc/knowledge-base", filename="faq.pdf", content_type="application/pdf")
with open("faq.pdf", "rb") as f:
    httpx.request(upload.method, upload.upload_url, content=f.read(),
                  headers=dict(upload.headers.additional_properties)).raise_for_status()

doc = client.upload_knowledge_doc_by_upload(
    "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    upload_id=upload.upload_id,
    filename="faq.pdf",
)
print(doc["id"])

List Knowledge Documents

List all documents in the agent's knowledge base.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

docs = client.list_knowledge_docs("8a1b2c3d-4e5f-6789-abcd-ef0123456789")
for doc in docs:
    print(doc["id"], doc["filename"], doc["status"])

Process Knowledge Document

Trigger embedding and indexing for a previously uploaded document. Ingestion is asynchronous — query_knowledge_base may return empty results until processing completes.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.process_knowledge_doc(
    "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    "b3c4d5e6-7f8a-9b0c-1d2e-3f4a5b6c7d8e",
)

Query Knowledge Base

Run a hybrid retrieval query against the agent's knowledge base. Returns RRF-ranked text chunks; score is the relevance value used for filtering, not the RRF score.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

results = client.query_knowledge_base(
    "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    query="What is the refund policy?",
)
for r in results.results:
    print(r.score, r.text)

Get Knowledge Texts

Retrieve the extracted text for each document in the knowledge base.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

texts = client.get_knowledge_texts("8a1b2c3d-4e5f-6789-abcd-ef0123456789")
for t in texts["documents"]:
    print(t['text'][:100], t['filename'])

Delete Knowledge Document

Remove a document from the agent's knowledge base.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.delete_knowledge_doc(
    "8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    "b3c4d5e6-7f8a-9b0c-1d2e-3f4a5b6c7d8e",
)

Calls

Trigger outbound calls and query call history. trigger_call places an actual phone call; the agent system_prompt and first_message drive the conversation through the STT, LLM, and TTS pipeline. The from_number must be registered to your tenant for outbound calling — the gateway rejects an omitted from_number with HTTP 422 (unless the server sets TWILIO_PHONE_NUMBER as a fallback). trigger_call and list_calls items return dicts; get_call_status returns a typed CallStatusResponse.

List Calls

List all call records for your tenant with optional pagination.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

page = client.list_calls(limit=10, offset=0)
for call in page.data:
    print(call.id, call.status, call.direction)

Create Call Record

Create a manual call record without triggering an actual call. Useful for logging external calls.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

call = client.create_call_record(
    agent_id="8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    direction="inbound",
    from_number="+14155551234",
    to_number="+18005550000",
    metadata={"source": "ivr-callback"},
)
print(call["id"])

Trigger Call

Place an outbound phone call with the specified agent. The from_number must be registered to your tenant.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

call = client.trigger_call(
    agent_id="8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    to_number="+14155551234",
    from_number="+18005550000",
    metadata={"customer_id": "cu_42"},
)
print(call["id"], call["status"])

Batch Calls

Trigger multiple outbound calls in a single request. Each recipient can have individual variables for prompt interpolation.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

batch = client.batch_calls(
    agent_id="8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    recipients=[
        {
            "to_number": "+14155551234",
            "from_number": "+18005550000",
            "variables": {"customer_name": "Alice"},
        },
        {
            "to_number": "+14155555678",
            "from_number": "+18005550000",
            "variables": {"customer_name": "Bob"},
        },
    ],
    name="Spring launch",
)
print(batch.batch_id, batch.status, batch.total)

Get Call Batch

Retrieve the status and progress of a batch call job.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

batch = client.get_call_batch("5e6f7a8b-9c0d-1e2f-3a4b-5c6d7e8f9a0b")
print(batch.status, batch.completed, batch.failed, batch.total)

Get Call

Retrieve a single call record by ID. Returns a typed CallResponse.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

call = client.get_call("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f")
print(call.status, call.duration_seconds)

Get Call Status

Poll the live status of a call by ID. Returns a typed CallStatusResponse.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

status = client.get_call_status("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f")
print(status.status)

Conversation (WebRTC)

Low-level WebRTC signalling for browser-to-agent voice conversations. Use the Realtime SDK for a higher-level interface.

Connect

Create a new WebRTC session. Returns session_id and ICE configuration.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

session = client.conversation_connect(agent_id="8a1b2c3d-4e5f-6789-abcd-ef0123456789")
print(session["session_id"], session["ice_config"])

Send Offer

Submit the WebRTC offer SDP. Returns the server's answer SDP.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

answer = client.send_offer(
    "3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d",
    sdp="v=0\r\no=- ...\r\n",
    type="offer",
)
print(answer["sdp"])

Send ICE Candidate

Relay ICE candidates to the server to complete peer connection setup.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.send_ice_candidate(
    "3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d",
    pc_id="3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d",
    candidates=[
        {
            "candidate": "candidate:842163049 1 udp 1677729535 ...",
            "sdp_mid": "0",
            "sdp_mline_index": 0,
        },
    ],
)

Get Session Status

Poll the status and metrics of an active WebRTC session.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

status = client.get_conversation_session_status("3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d")
print(status["status"], status["duration_s"], status["turn_count"])

End Session

Terminate an active WebRTC conversation session.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.end_conversation_session("3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d")

Send Tool Result

Return the result of a tool call to the agent during an active session.

python
import json
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.send_tool_result(
    "3f2a7b1c-8d4e-4a5b-9c2d-1e0f3a4b5c6d",
    tool_call_id="call_abc123",
    result=json.dumps({"order_status": "shipped"}),
)

Conversations

Retrieve conversation records, transcripts, and recordings from completed calls. get_conversation returns a typed ConversationResponse and get_transcript returns a list of typed ConversationTurnResponse items, so attribute access works on both. The downloadable recording lives on Kora as get_conversation_audio (returns raw bytes); the equivalent AethexAI methods return signed URLs or stream metadata instead, so use Kora when you want the file bytes directly.

List Conversations

List completed conversation records with optional pagination.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

page = client.list_conversations(limit=10, offset=0)
for conv in page.data:
    print(conv.id, conv.status, conv.total_duration_ms)

Search Conversations

Full-text search across conversation transcripts.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

response = client.search_conversations("refund policy", limit=10)
for hit in response["results"]:
    print(hit["conversation_id"], hit["text"])

Get Conversation

Retrieve a single conversation record. Returns a typed ConversationResponse.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

conv = client.get_conversation("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f")
print(conv.id, conv.status, conv.total_duration_ms)

Get Transcript

Retrieve the turn-by-turn transcript for a conversation. Returns a list of typed ConversationTurnResponse items.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

turns = client.get_transcript("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f")
for turn in turns:
    print(f"{turn.role}: {turn.text}")

Get Audio URL

Get a short-lived signed URL to the conversation audio recording.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

audio = client.get_audio("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f")
print(audio["url"], audio["format"], audio["expires_in"])

Get Audio Bytes

Download the conversation audio recording as raw bytes using the Kora client.

python
from aethexai import Kora

kora = Kora(base_url="https://api.aethexai.com", api_key="ae_live_...")

audio = kora.get_conversation_audio("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f")
with open("conversation.wav", "wb") as f:
    f.write(audio)

Revoke Audio Token

Revoke a previously issued audio playback token to prevent further access.

python
from urllib.parse import urlparse, parse_qs
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

# Mint a URL, then extract its token to revoke it.
audio = client.get_audio("c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f")
token = parse_qs(urlparse(audio["url"]).query)["token"][0]

client.revoke_audio_token(
    "c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f",
    token=token,
)

Submit Feedback

Attach a quality rating and optional comment to a conversation.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.submit_feedback(
    "c1d2e3f4-5a6b-7c8d-9e0f-1a2b3c4d5e6f",
    rating=5,
    comment="Resolved my issue quickly.",
)

Transcription

Transcribe audio files synchronously or submit them for asynchronous processing. The sync method blocks until the result is ready. The async variant returns a job whose status you can poll.

Transcribe (Sync)

Transcribe audio synchronously using the Kora client. Blocks until the result is ready.

python
from aethexai import Kora

kora = Kora(base_url="https://api.aethexai.com", api_key="ae_live_...")

with open("recording.wav", "rb") as f:
    result = kora.transcribe(f.read(), language="english")
print(result.text)

Transcribe (Async)

Submit audio for asynchronous transcription. Returns a job ID to poll.

python
from aethexai import Kora

kora = Kora(base_url="https://api.aethexai.com", api_key="ae_live_...")

with open("long_recording.wav", "rb") as f:
    job = kora.transcribe_async(
        f.read(),
        language="english",
        webhook_url="https://example.com/webhooks/transcription",
    )
print(job.id, job.status)

Transcribe by Upload

Transcribe audio that was previously uploaded via a presigned URL. Synchronous.

python
from aethexai import AethexAI
import httpx

client = AethexAI(api_key="ae_live_...")

upload = client.presign_upload(kind="audio/transcribe", filename="recording.wav", content_type="audio/wav")
with open("recording.wav", "rb") as f:
    httpx.request(upload.method, upload.upload_url, content=f.read(),
                  headers=dict(upload.headers.additional_properties)).raise_for_status()

result = client.transcribe_audio_by_upload(upload_id=upload.upload_id, language="english")
print(result.text)

Transcribe Async by Upload

Submit presigned-URL audio for asynchronous transcription with webhook delivery.

python
from aethexai import AethexAI
import httpx

client = AethexAI(api_key="ae_live_...")

upload = client.presign_upload(kind="audio/transcribe", filename="long.wav", content_type="audio/wav")
with open("long_recording.wav", "rb") as f:
    httpx.request(upload.method, upload.upload_url, content=f.read(),
                  headers=dict(upload.headers.additional_properties)).raise_for_status()

job = client.transcribe_audio_async_by_upload(
    upload_id=upload.upload_id,
    language="english",
    webhook_url="https://example.com/webhooks/transcription",
)
print(job.id, job.status)

Get Transcription Job

Poll the status of an async transcription job. Returns the result when status is completed.

python
from aethexai import Kora

kora = Kora(base_url="https://api.aethexai.com", api_key="ae_live_...")

job = kora.get_transcribe_job("a1c4e7d2-5b9f-4e83-8c1a-7e0b9d4f2a16")
print(job.status, job.text if job.status == "completed" else job.error_message)

Cancel Transcription Job

Cancel a pending or in-progress async transcription job.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.cancel_transcription_job("a1c4e7d2-5b9f-4e83-8c1a-7e0b9d4f2a16")

Text-to-Speech

Convert text to speech. synthesize_speech returns the full audio as a complete WAV (header included, so the file is playable as-is). stream_speech yields raw 16-bit mono PCM frames at 24 kHz for lower time-to-first-byte playback — wrap them in a WAV header yourself, or pipe straight into a player that consumes PCM (for example, ffplay -f s16le -ar 24000). Keep realtime synthesize/stream inputs to 650 characters or fewer; use batch_synthesize for long-form scripts up to 3000 characters per item.

Synthesize Speech

Convert up to 650 characters of text to a full WAV audio file. The header is included so the file is playable as-is.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

audio = client.synthesize_speech(
    text="Hello, welcome to AethexAI!",
    language="english",
)
with open("output.wav", "wb") as f:
    f.write(audio)

Stream Speech

Stream up to 650 characters of speech as raw 16-bit mono PCM chunks at 24 kHz for lower time-to-first-byte.

python
import wave
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

with wave.open("output.wav", "wb") as wav:
    wav.setnchannels(1)
    wav.setsampwidth(2)
    wav.setframerate(24_000)
    for chunk in client.stream_speech(
        text="Streaming hello.",
        language="english",
    ):
        wav.writeframes(chunk)

Batch Synthesize

Submit a list of texts for asynchronous speech synthesis with webhook delivery. Each item can be up to 3000 characters; the platform splits long items into safe backend chunks and returns one WAV per item.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

batch = client.batch_synthesize(
    language="english",
    items=[
        {"text": "First message."},
        {"text": "Second message."},
    ],
    webhook_url="https://example.com/webhooks/tts",
)
print(batch.batch_id, batch.status, batch.total)

Get TTS Batch

Retrieve the status and per-item results of a TTS batch job.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

batch = client.get_tts_batch("8e7d6c5b-4a3b-2c1d-0e9f-8a7b6c5d4e3f")
print(batch.status, batch.completed, batch.failed, batch.total)
for item in batch.results:
    print(item.index, item.status, item.audio_url)

Voices

List and retrieve available voices. Returns typed VoiceResponse objects so attribute access works.

List Voices

List all voices available to your tenant with optional language filter and pagination.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

voices = client.list_voices(language="english", limit=20)
for v in voices:
    print(v.id, v.name, v.language)

Get Voice

Retrieve a single voice by ID or name.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")
voices = client.list_voices(language="english", limit=1)

voice = client.get_voice(voices[0].id)
print(voice.id, voice.name, voice.supports_dialect_style)

Preview Voice

Generate a short audio clip to preview a voice. Workaround: use synthesize_speech until the preview_voice UTF-8 bug is fixed.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")
voices = client.list_voices(language="english", limit=1)

# Workaround: use synthesize_speech until preview_voice's UTF-8 bug is fixed.
preview = client.synthesize_speech(
    voice_id=voices[0].id,
    text="Welcome to Aethex AI.",
    language="english",
)
with open("preview.wav", "wb") as f:
    f.write(preview)

Phone Numbers

Register, list, and manage phone numbers for inbound and outbound calling.

List Phone Numbers

List all phone numbers registered to your tenant.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

page = client.list_phone_numbers(limit=20, offset=0)
for number in page.data:
    print(number["id"], number["phone_number"], number["provider"])

Register Twilio Number

Link a Twilio phone number to an agent for inbound and outbound calling.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

number = client.register_twilio_phone_number(
    twilio_account_id="0a1b2c3d-4e5f-6789-abcd-ef0123456789",
    phone_number="+18005550000",
    agent_id="8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    friendly_name="Sales line",
)
print(number["id"])

Register SIP Number

Link a SIP trunk phone number to an agent.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

number = client.register_sip_phone_number(
    phone_number="+18005550000",
    trunk_id="2a4b6c8d-1e3f-5a7b-9c0d-2e4f6a8b0c1d",
    agent_id="8a1b2c3d-4e5f-6789-abcd-ef0123456789",
    friendly_name="Inbound support",
)
print(number["id"])

Get Phone Number

Retrieve a single phone number record by ID.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

number = client.get_phone_number("9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d")
print(number)

Update Phone Number

Update the assigned agent or configuration for a registered phone number.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.update_phone_number(
    "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
    agent_id="8a1b2c3d-4e5f-6789-abcd-ef0123456789",
)

Release Phone Number

Remove a registered phone number from your tenant.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.release_phone_number("9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d")

Set Phone Number Routing

Configure fallback routing for a phone number (e.g. forward on no-answer).

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.set_phone_number_routing(
    "9a8b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d",
    fallback_action="forward",
    fallback_number="+18005550000",
    max_ring_seconds=30,
)

Twilio Accounts

Register and manage Twilio credentials used for outbound calling.

Register Twilio Account

Connect a Twilio account to your AethexAI tenant using an Account SID and Auth Token.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

account = client.register_twilio_account(
    account_sid="ACxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    auth_token="your_twilio_auth_token",
    friendly_name="Production Twilio",
)
print(account.id)

List Twilio Accounts

List all Twilio accounts registered to your tenant.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

page = client.list_twilio_accounts(limit=20, offset=0)
for acct in page.data:
    print(acct["id"], acct["friendly_name"])

Get Twilio Account

Retrieve a single Twilio account record by ID.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

account = client.get_twilio_account("0a1b2c3d-4e5f-6789-abcd-ef0123456789")
print(account)

Release Twilio Account

Disconnect a Twilio account from your tenant.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.release_twilio_account("0a1b2c3d-4e5f-6789-abcd-ef0123456789")

Recordings

List and download call recordings.

List Recordings

List all recordings for your tenant with optional pagination.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

page = client.list_recordings(limit=10, offset=0)
for rec in page.data:
    print(rec["id"], rec["duration_seconds"])

Get Recording

Retrieve a single recording record by ID.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

rec = client.get_recording("5e4f3a2b-1c0d-9e8f-7a6b-5c4d3e2f1a0b")
print(rec)

Get Recording Audio

Get a signed URL to the recording audio and download it.

python
import httpx
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

result = client.get_recording_audio("5e4f3a2b-1c0d-9e8f-7a6b-5c4d3e2f1a0b")
audio = httpx.get(result["url"]).content
with open("recording.wav", "wb") as f:
    f.write(audio)

Delete Recording

Permanently delete a recording.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.delete_recording("5e4f3a2b-1c0d-9e8f-7a6b-5c4d3e2f1a0b")

Models

Query the available LLM models for your deployment.

List Models

List all models with optional include_unavailable flag.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

models = client.list_models(include_unavailable=False)
for model in models:
    print(model.id, model.provider, model.available)

Uploads

Get presigned URLs for direct file uploads to object storage.

Presign Upload

Request a presigned URL for uploading a file. PUT the bytes to upload_url with the supplied headers, then pass upload_id to the registration endpoint.

python
from aethexai import AethexAI
import httpx

client = AethexAI(api_key="ae_live_...")

upload = client.presign_upload(
    kind="doc/knowledge-base",
    filename="faq.pdf",
    content_type="application/pdf",
)

with open("faq.pdf", "rb") as f:
    httpx.request(
        upload.method,
        upload.upload_url,
        content=f.read(),
        headers=dict(upload.headers.additional_properties),
    ).raise_for_status()
print(upload.upload_id)

Usage & Billing

Query usage metrics, configure billing triggers, and manage webhook secrets.

Get Usage

Retrieve raw usage counters for your tenant.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

usage = client.get_usage()
print(usage)

Get Usage Summary

Retrieve aggregated usage summary for the current billing period.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

summary = client.get_usage_summary()
print(summary)

Get Daily Usage

Retrieve day-by-day usage for the past N days.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

for day in client.get_daily_usage(days=30):
    print(day.date, day.count, day.total_tokens, day.voice_seconds)

Get Monthly Usage

Retrieve month-by-month usage history.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

for month in client.get_monthly_usage():
    print(month.month, month.count, month.total_tokens, month.voice_seconds)

Create Trigger

Configure a usage threshold trigger that fires a webhook when the threshold is crossed.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

trigger = client.create_trigger(
    resource_type="voice_call",
    threshold_value="180000",  # string preserves precision; server parses to Decimal
    threshold_type="count",
    period="monthly",
    event_callback_url="https://example.com/webhooks/usage",
)
print(trigger.id)

List Triggers

List all usage threshold triggers for your tenant.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

for trigger in client.list_triggers():
    print(trigger.id, trigger.resource_type, trigger.threshold_value, trigger.is_active)

Update Trigger

Update the threshold or configuration of an existing trigger.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.update_trigger(
    "4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a",
    threshold_value="250000",
)

Rotate Webhook Secret

Rotate the shared webhook secret for trigger delivery. The SDK call rotates the secret but does not return its value; if you need to capture the new secret, send the raw HTTP request instead, which returns it in the response. Each call rotates and revokes the previous secret, so use one approach or the other.

List Trigger Firings

Retrieve the delivery history for a trigger.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

firings = client.list_trigger_firings("4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a", limit=50)
for firing in firings:
    print(firing.id, firing.fired_at, firing.delivery_status, firing.attempt_count)

Redeliver Firing

Retry delivery of a previously failed trigger firing.

python
from aethexai import AethexAI

client = AethexAI(api_key="ae_live_...")

client.redeliver_firing(
    "4d5e6f7a-8b9c-0d1e-2f3a-4b5c6d7e8f9a",
    "7c6d5e4f-3a2b-1c0d-9e8f-7a6b5c4d3e2f",
)

Async Support

AsyncAethexAI mirrors the sync client method-for-method. Use it with asyncio, FastAPI, workers, or any async framework where you want non-blocking HTTP calls.

python
import asyncio
from aethexai import AsyncAethexAI

async def main():
    async with AsyncAethexAI(api_key="ae_live_...") as client:
        voices = await client.list_voices(language="english")
        agent = await client.create_agent(
            name="Async Bot",
            system_prompt="You are a helpful customer support agent.",
            voice_id=voices[0].id,
        )
        call = await client.trigger_call(
            agent_id=agent.id,
            to_number="+14155551234",
            from_number="+18005550000",
        )
        print(call["id"], call["status"])

asyncio.run(main())

Realtime Conversations

Use the realtime extra for full-duplex WebRTC conversations with the same voice pipeline your end users get from the dashboard. Requires the realtime extra · install with pip install "aethexai[realtime]". The realtime extra pulls aiortc and PyAV; PyAV needs the FFmpeg development headers on the host before the wheel can build (apt install libavformat-dev libavfilter-dev libavdevice-dev on Debian/Ubuntu, brew install ffmpeg on macOS).

Note
By default Conversation attaches a silent input track, so the agent will only hear silence until you wire a real audio source. Pass any aiortc MediaStreamTrack (for example one backed by sounddevice) via the audio_input= keyword to send mic input. The agent_id below must be the UUID of an agent you have already created · derive it from list_agents() rather than hardcoding a placeholder.
python
import asyncio
from aethexai import AsyncAethexAI
from aethexai.realtime import Conversation, ConversationCallbacks

async def main():
    async with AsyncAethexAI(api_key="ae_live_...") as client:
        page = await client.list_agents(limit=1)
        if not page.data:
            raise SystemExit("Create an agent before starting a realtime call")
        agent_id = page.data[0].id

        conversation = Conversation(
            client,
            agent_id=agent_id,
            callbacks=ConversationCallbacks(
                on_agent_text=lambda text: print("agent:", text),
                on_user_transcript=lambda text: print("user:", text),
            ),
            # audio_input=<your aiortc MediaStreamTrack from sounddevice>,
        )
        await conversation.start()
        await asyncio.sleep(30)
        await conversation.end()

asyncio.run(main())

Error Handling

The SDK raises typed exceptions for API and transport errors. All exceptions inherit from AethexError. APIStatusError subclasses carry the HTTP status code, error code, headers, and raw response body. RateLimitError includes a retry_after property.

python
from aethexai import (
    AethexAI,
    AethexError,
    APIStatusError,
    AuthenticationError,
    NotFoundError,
    RateLimitError,
    ValidationError,
)

client = AethexAI(api_key="ae_live_...")

try:
    agent = client.get_agent("00000000-0000-0000-0000-000000000000")
except NotFoundError:
    print("Agent not found")
except AuthenticationError:
    print("Invalid API key")
except RateLimitError as e:
    print(f"Rate limited. Retry after {e.retry_after}s")
except ValidationError as e:
    print(f"Invalid request: {e.message}")
except APIStatusError as e:
    print(f"API error {e.status_code}: {e.message}")
except AethexError as e:
    print(f"SDK error: {e}")