Build Your Own AI Voice Application with 3CX Programmable Extensions
- Introduction
- What You Will Build
- Before You Begin
- Step 1: Download the Examples
- Step 2: Create a 3CX Service Principal
- Step 3: Choose an AI Provider
- Step 4: Create the Provider Configuration
- OpenAI
- Gemini
- xAI
- Alibaba Qwen
- Step 5: Start the Application
- OpenAI
- Gemini
- xAI
- Alibaba Qwen
- Step 6: Call and Test the Application
- Make an Internal Call
- Make an External Call
- Suggested Tests
- Customise the Agent
- Use 3CX MCP Tools
- Connect Additional MCP Servers
- Moving Beyond the Receptionist Example
- Production Checklist
- Troubleshooting
- yarn Is Not Recognised
- PBX Authentication Returns 401 or 403
- The Application Starts but Does Not Receive Calls
- An MCP Tool Appears Disabled
- Transfers or Voicemail Fail
- The AI Provider Rejects the Connection
- Audio Is Delayed or the Agent Is Frequently Interrupted
Connect an externally hosted AI voice application to 3CX using the Call Control API, the Call Control SDK and a supported real-time AI provider.
Introduction
3CX Programmable Extensions allow an externally hosted application to connect to the PBX and operate like a native extension. The application can receive calls, stream audio in both directions and control call routing through the 3CX Call Control API.
The Agentic Call Control examples provide working Node.js applications for:
- OpenAI Realtime
- Google Gemini Live
- xAI Grok Voice
- Alibaba Cloud Qwen Omni Realtime
Each example uses a single bidirectional real-time audio session. Speech recognition, reasoning and speech generation are handled by the selected AI provider, while 3CX continues to provide the telephony, call routing, extensions, SIP trunks and DIDs.
The examples connect through published 3CX APIs and do not require changes to the PBX source code. They also connect to the 3CX MCP endpoint so the voice application can use authorised PBX tools such as phonebook lookup. Optional external MCP servers can be added for calendars, CRMs and other business systems.
Which option should I use?
This guide covers Programmable Extensions, where the application runs outside 3CX on infrastructure you manage. For a ready-to-configure solution, use the built-in 3CX AI Agents. For custom applications that run directly on the 3CX Server, use AI Call Scripts.
What You Will Build
By the end of this guide, you will have an external AI voice application that can:
- Receive internal calls through its 3CX Client ID.
- Receive external calls through an assigned DID.
- Hold a real-time voice conversation using your selected AI provider.
- Search the 3CX phonebook through MCP.
- Transfer a call, send it to voicemail or end it through 3CX Call Control.
- Connect to additional MCP servers and expose selected tools to the model.
The supplied agent profile implements a basic receptionist flow. It is intended as a starting point and can be extended for appointment booking, customer information, surveys, internal help desks and other workflows.
Before You Begin
You need:
- A 3CX V20 Update 10 system with Call Control API access.
- Administrator access to create an API Service Principal.
- Node.js 20 or later on the computer or server that will host the application.
- The Yarn version bundled with the repository.
- An API key and available quota for at least one supported AI provider.
- Network access from the application host to the 3CX HTTPS FQDN and the selected provider's WebSocket endpoints.
Step 1: Download the Examples
Clone or download the Agentic Call Control Github repository
From a terminal, change to the repository root and install all workspace dependencies:
yarn install
If the yarn command is not available, enable Corepack first:
corepack enable
yarn install
Do not run yarn install separately in every provider directory. The repository is a Yarn workspace and should be installed from its root.
Step 2: Create a 3CX Service Principal
Create the credentials the external application will use to authenticate with the PBX.
- Sign in to the 3CX Web Client and open Admin.
- Go to Admin > Integrations > API.
- Click Add to create a Service Principal.
- Enter a Client ID, for example ai-receptionist. This becomes the application's appId and the internal number users can dial to call the application.
- Enable 3CX Call Control API access for the application.
- Optionally assign a DID if external callers must be able to reach it directly.
- Optionally select the extensions the application is permitted to monitor or control. Grant only the access required by the intended workflow.
- Save the Service Principal.
- Copy the generated API key or Client Secret immediately. It is used as appSecret and will be displayed only once.
Step 3: Choose an AI Provider
Use one of the included examples.
Provider | Example directory | Provider credential | Start command |
OpenAI Realtime | examples/openai-realtime | openaiApiKey | yarn start:openai |
Google Gemini Live | examples/gemini-realtime | geminiApiKey | yarn start:gemini |
xAI Grok Voice Agent | examples/xai-realtime | xaiApiKey | yarn start:xai |
Alibaba Qwen Omni Realtime | examples/alibaba-qwen-realtime | dashscopeApiKey | yarn start:alibaba-qwen |
Create the API key in the selected provider's console and store it securely:
For current model availability, voices, regions, pricing and rate limits, refer to the selected provider's documentation and the README in the corresponding example directory.
Qwen region note: DashScope credentials and endpoints are region-specific. Use the endpoint required for the region and workspace in which the API key was created.
Step 4: Create the Provider Configuration
Copy config.yaml.example to config.yaml in the selected example directory.
OpenAI
cp examples/openai-realtime/config.yaml.example examples/openai-realtime/config.yaml
Gemini
cp examples/gemini-realtime/config.yaml.example examples/gemini-realtime/config.yaml
xAI
cp examples/xai-realtime/config.yaml.example examples/xai-realtime/config.yaml
Alibaba Qwen
cp examples/alibaba-qwen-realtime/config.yaml.example examples/alibaba-qwen-realtime/config.yaml
On Windows PowerShell, use Copy-Item instead of cp.
Open the new config.yaml and enter the common 3CX values:
appId: ai-receptionist
appSecret: your-3cx-api-key
pbxBase: https://your-pbx.example.com
companyName: Your Company
agentName: Assistant
initialGreeting: Thank you for calling. How can I help you today?
Keep the agentProfile value supplied by the selected example. OpenAI, Gemini and xAI use receptionist; Qwen includes separate English and Chinese profiles.
Next, set the credential for the selected provider. For example, the OpenAI configuration contains:
openaiApiKey: sk-your-openai-api-key
Use the provider's supplied config.yaml.example as the source of truth for model, voice, voice activity detection and provider-specific settings. For Qwen, keep the provider's region-specific base URL configuration.
Security: config.yaml contains secrets. It is excluded by the supplied .gitignore, but you should still avoid sharing it, committing it or including it in support logs. Use a secret manager or environment-based deployment method for production.
Step 5: Start the Application
Run the command for the selected provider from the repository root.
OpenAI
yarn start:openai
Gemini
yarn start:gemini
xAI
yarn start:xai
Alibaba Qwen
yarn start:alibaba-qwen
The exact startup output varies by provider. A successful start should confirm that:
- The application authenticated with 3CX.
- The Call Control SDK and WebSocket connection are active.
- The application connected to the 3CX MCP endpoint.
- The enabled MCP tools were loaded.
- The call handler is initialised and the application is ready to accept calls.
Step 6: Call and Test the Application
Make an Internal Call
From a registered 3CX extension, dial the Service Principal Client ID configured as appId.
For example, if the Client ID is ai-receptionist, dial ai-receptionist from the 3CX Web Client, desktop app, mobile app or a provisioned phone.
Make an External Call
If you assigned a DID to the Service Principal, call that number from an external phone.
Suggested Tests
Test the complete workflow before customising it:
- Confirm that the agent answers with the configured greeting.
- Ask to speak with a known phonebook contact.
- Confirm that the agent searches the phonebook through MCP.
- Test a successful transfer.
- Test the unavailable-user and voicemail path.
- Interrupt the agent while it is speaking to verify barge-in behaviour.
- End the call and confirm that the application releases the call correctly.
Stop the application with Ctrl+C.
Customise the Agent
Basic settings such as the company name and agent name are stored in config.yaml.
More detailed behaviour is defined by the YAML profile in the selected example's agents directory. Depending on the provider example, the default profile is named receptionist.yaml
The profile controls areas such as:
- The role and system prompt.
- Greetings and language behaviour.
- Call screening requirements.
- Availability checks before transfer.
- Allowed call actions.
- Blocked extensions.
- Spam, hostility and non-collaborative caller policies.
- The MCP tools exposed to the model.
Restart the application after changing either config.yaml or the selected agent profile.
Keep prompts and tool permissions aligned. Telling the model that it can perform an action does not grant the underlying application or Service Principal permission to perform it.
Use 3CX MCP Tools
At startup, the examples connect to the 3CX MCP endpoint and discover the tools available to the authenticated Service Principal.
Only the tools listed in the agent profile's mcpTools allowlist are exposed to the AI model. The default receptionist profile enables phonebook lookup:
mcpTools:
- list_phonebook
The startup log shows the tools discovered from the server and whether each one is enabled. To expose another authorised tool, add its exact name to mcpTools and restart the application.
Restrict the list to the smallest set of tools required by the workflow. A tool that is not exposed to the model cannot be called by the model.
Connect Additional MCP Servers
Optional MCP servers can be configured under customMcpServers in config.yaml. This can give the voice application access to approved calendar, CRM or business-process tools.
The examples support auth.type: bearer or none for convenience during testing. For a quick trial without running your own MCP server, use a hosted MCP aggregator such as Smithery AI or Zapier. Create an account and paste the remote URL and bearer token into customMcpServers, then enable the discovered tool names in mcpTools.
customMcpServers:
- name: GoogleCalendar
url: https://mcp.example.com/your-server
auth:
type: bearer
token: your-mcp-bearer-token
enabled: true
Add each tool you want to expose to the agent profile using its exact name:
mcpTools:
- list_phonebook
- googlecalendar.quick_add
Tools discovered from custom MCP servers are merged with the available 3CX MCP tools, but the profile allowlist remains in control of which tools the model can use.
When adding external MCP servers:
- Use least-privilege credentials.
- Expose only the required tools.
- Validate tool parameters server-side.
- Require approval for sensitive or irreversible operations where appropriate.
- Do not place long-lived production secrets directly in source control.
Moving Beyond the Receptionist Example
The included receptionist logic demonstrates phonebook search, transfer, voicemail and call termination. The same architecture can be extended to support workflows such as:
- Appointment scheduling.
- Customer or account-information lookup.
- Automated surveys.
- Internal IT or HR help desks.
- CRM ticket creation and updates.
- Order-status or delivery-information services.
- Voice interfaces for custom business applications.
The application remains responsible for business logic, validation, error handling and tool security. 3CX provides the call connection, audio streaming and call-control functions, while the selected AI provider handles the real-time conversation.
Production Checklist
Before moving a custom application beyond testing:
- Run it as a managed service with automatic restart and health monitoring.
- Protect API credentials with a secret manager and rotate them periodically.
- Restrict the Service Principal to the required extensions and functions.
- Review the AI provider's data-processing, retention and regional availability policies.
- Inform callers and obtain consent where recording, transcription or AI disclosure is required.
- Monitor provider usage, rate limits and costs.
- Add timeouts, retry handling and a non-AI fallback route.
- Test transfer, voicemail, failure and disconnect paths under realistic call conditions.
- Review every enabled MCP tool and protect sensitive actions with additional validation or approval.
Troubleshooting
yarn Is Not Recognised
Make sure Node.js 20 or later is installed, then enable Corepack:
corepack enable
Run yarn install again from the repository root.
PBX Authentication Returns 401 or 403
Check that appId, appSecret and pbxBase match the Service Principal. Confirm that Call Control API access is enabled and that the 3CX licence and permissions permit the requested operation.
The Application Starts but Does Not Receive Calls
Confirm that the application is still running, dial the correct Client ID and verify that the DID is assigned to the Service Principal when testing external calls.
An MCP Tool Appears Disabled
Copy the exact tool name shown in the startup log into the profile's mcpTools list, then restart the application. Also confirm that the Service Principal is authorised to use the tool.
Transfers or Voicemail Fail
Verify that the destination is valid and accessible to the Service Principal. If call screening is enabled in the profile, confirm that the required screening fields were collected before the transfer was attempted.
The AI Provider Rejects the Connection
Check the API key, account billing, model access, region, quota and WebSocket connectivity. For Qwen, confirm that the API key and endpoint belong to the same region and workspace.
Audio Is Delayed or the Agent Is Frequently Interrupted
Check network latency and packet loss between the application host, 3CX and the AI provider. Review the provider-specific voice activity detection and audio settings in config.yaml.
Last Updated
This guide was last updated on 9 September 2026