An agent is a complete voice persona. When you create one with just a name, it is immediately usable — OneInbox automatically sets up a default LLM, a default voice, and a default system prompt. You only need to change these if you want to customise them.
Component
Default
Change it when…
LLM (AI brain)
Auto-created with a general system prompt
You want a specific persona, script, or temperature
Voice
Default voice pre-configured
You want a specific voice from ElevenLabs or Cartesia
System prompt
General-purpose assistant
You want the agent to follow specific instructions or scripts
Language
en
You need the agent to transcribe a different language
Tools
None
You want the agent to take actions (SMS, transfer, capture data)
A single agent handles browser calls (via the Web SDK) and direct phone calls — both outbound and inbound — you don’t need a separate agent per call type.
Pass any fields you want configured from the start. All fields except name are optional.
curl -X POST https://api.oneinbox.ai/v1/agents \ -H "Authorization: Bearer <api_key>" \ -H "Content-Type: application/json" \ -d '{ "name": "Acme Support Agent", "language": "en", "first_message": "Hi! Thanks for reaching out to Acme. How can I help you today?", "tts": { "provider": "elevenlabs", "voice_id": "<imported_voice_id>" }, "silence_timeout_seconds": 10, "max_duration_seconds": 600, "interruption_sensitivity": 0.6, "enable_recording": true, "voicemail_detection": true, "voicemail_message": "Hi, please leave a message and we'll call you back." }'
The llm_id in the response is the auto-created AI model. Use it to set the system prompt, attach tools, or link knowledge bases — regardless of which option you used.Your agent is ready immediately. Test it with a quick browser call — no phone number needed, runs entirely over the internet (same mechanism the Web SDK uses):
Out of the box the agent works with a general-purpose system prompt, a default voice, and a default LLM. To give your agent a specific personality or script, update the LLM model using the llm_id from the create response:
curl -X PATCH https://api.oneinbox.ai/v1/models/<llm_id> \ -H "Authorization: Bearer <api_key>" \ -H "Content-Type: application/json" \ -d '{ "system_prompt": "You are a helpful sales rep for Acme Corp. Your goal is to qualify leads and book product demos. Keep all replies under two sentences. Be warm and direct.", "temperature": 0.7 }'
Changes apply to new calls immediately. One LLM model can power multiple agents — to share a brain across agents, PATCH the agent with { "llm_id": "llm_xyz789" }. Update the model once and all agents using it pick up the change.To use a self-hosted or third-party LLM, set provider to "custom" and supply custom_websocket_url. The URL can be wss://, ws://, https://, or http:// — the server must expose an OpenAI-compatible streaming chat completions interface.
curl -X POST https://api.oneinbox.ai/v1/models \ -H "Authorization: Bearer <api_key>" \ -H "Content-Type: application/json" \ -d '{ "name": "My self-hosted LLM", "provider": "custom", "custom_websocket_url": "wss://your-llm-server.example.com/v1/chat/completions", "system_prompt": "You are a helpful voice assistant.", "temperature": 0.7 }'
Tools (send SMS, capture caller data, transfer calls, book meetings, etc.) are attached to the LLM model, not the agent directly.Why: the LLM model is what decides what to do during a conversation. Tools are the actions it can take — so they live there. Any agent using that model inherits all its tools automatically.To add a tool, first create it, then attach it to the llm_id from your agent:
# 1. Create a tool (example: capture caller info)curl -X POST https://api.oneinbox.ai/v1/tools \ -H "Authorization: Bearer <api_key>" \ -H "Content-Type: application/json" \ -d '{ "name": "capture_lead_info", "type": "extract_information", "description": "Extract the caller name, budget, and timeline from the conversation.", "extraction_schema": { "fields": [ { "name": "caller_name", "type": "string", "description": "Full name of the caller" }, { "name": "budget", "type": "string", "description": "Budget the caller mentioned" }, { "name": "timeline", "type": "string", "description": "Their decision timeline" } ] } }'# Save the returned tool "id"# 2. Attach it to the agent's LLM modelcurl -X PATCH https://api.oneinbox.ai/v1/models/<llm_id> \ -H "Authorization: Bearer <api_key>" \ -H "Content-Type: application/json" \ -d '{ "tool_ids": ["<tool_id>"] }'
→ Tools guide — all 7 tool types with full examples
STT converts the caller’s voice into text that the LLM can understand. Set the transcriber object on the agent to choose the provider and model.All STT providers below are platform-provided — no credential needed.
Provider
Models
Best for
Deepgram
nova-3 (default), flux-en, flux-multi
Low latency, high accuracy. nova-3 recommended for most use cases
Set language to match the caller’s language — e.g. "hi" for Hindi, "ja" for Japanese. Use flux-multi for multilingual calls where the language is unknown.
TTS converts the agent’s text replies into spoken audio. Set the tts object on the agent to choose the provider, voice, and speed.All TTS providers below are platform-provided — no credential needed.
Dynamic variables let you personalise an agent’s first_message, voicemail_message, and system_prompt per call — without creating a separate agent per lead. Write placeholders with single braces ({variable_name}) in any of those fields, then pass the actual values when you start the call.
The agent opens with: “Hi Priya, this is Aria calling about Acme Outreach.”Two layers — how they combine:
Layer
Where set
Priority
dynamic_variables on the agent
Agent config — same for every call
Lower (default fallback)
variables on the call
Call request — per-call
Higher (overrides agent defaults)
At call start, OneInbox builds the final variable map by merging both layers (call values win on collision), then substitutes every {placeholder} in the templates before the agent says a word. The LLM and TTS only ever see the resolved strings — never the raw placeholders.
Use single braces — {lead_name}, not {{lead_name}}. Double braces are not interpolated and appear as literal text.
The single-agent GET includes a read-only effective_system_prompt field — the exact system prompt the agent is given at call time: the LLM’s system_prompt with job_description prepended as a # Role block. This is what the LLM actually receives, assembled the same way the worker does at runtime.
{ "id": "agt_abc123", "llm_id": "llm_xyz789", "job_description": "You are a friendly sales rep at Acme.", "effective_system_prompt": "# Role\nYou are a friendly sales rep at Acme.\n\nYou are a helpful voice assistant.", "..."}
effective_system_prompt is only populated on GET /v1/agents/{id}. It is null on the list endpoint to avoid an LLM lookup per row. Per-call variable interpolation and knowledge base chunks are resolved at runtime and are not reflected here.
Permanently removes the model. Agents currently using this model will lose their LLM config — reassign them first with { "llm_id": "<replacement_model_id>" }.