PhonixPBX can be controlled by scripts and other programs. The REST API under /api/v1 offers the same functions as the web interface and uses the same rules for validation, secrets and pending changes. The MCP server under /api/mcp makes the same functions available to AI assistants. Both are reached over HTTPS on the address of the web interface.
Interactive documentation
https://<pbx>/api/docs– Swagger UI with every endpoint, its parameters and response format. You can try out requests there: click Authorize and enter a token. The footer of the web interface links here (API).https://<pbx>/api/v1/openapi.json– the OpenAPI schema, for example to generate a client.
API tokens
Scripts authenticate with a bearer token. Create tokens under Advanced → API tokens or with phonix token create. A token starts with phx_ and is shown only once, when it is created; the PBX stores only a hash of it.
| Property | Meaning |
|---|---|
| Access Read-only | GET requests only, and only the read-only MCP tools. Voicemail and conference PINs are left out of the responses. |
| Access Read-write | All requests: create, change, delete, apply. |
| May place calls | Allows click-to-call (POST /api/v1/calls, MCP tool originate_call), independently of the access: a read-only token with this flag can place calls but not change the configuration. Off by default – calls to external numbers can cost money. |
| Expires in (days) | Validity; empty means the token never expires. |
A token acts with the rights of the administrator who owns it, and its changes appear under that name in the audit log. Disabled and expired tokens are rejected. Repeated requests with wrong tokens are blocked for a few minutes, like failed logins.
Send the token in the Authorization header:
curl -H "Authorization: Bearer phx_..." https://pbx.example.com/api/v1/status
While the PBX uses its self-signed certificate, add -k to curl or, better, install a proper certificate.
Objects
Every kind of object has the same five endpoints:
| Path | Objects |
|---|---|
/api/v1/phones | Phones |
/api/v1/providers | Providers |
/api/v1/callgroups | Call groups |
/api/v1/conferences | Conference rooms |
/api/v1/applications | Dialplan applications |
/api/v1/ivr-menus | IVR menus |
/api/v1/business-hours | Business hours |
/api/v1/ami-users | Asterisk manager users |
GET <path>lists all objects,GET <path>/{id}returns one.POST <path>creates an object (answer201).PUT <path>/{id}replaces an object: send all fields, as for a create.DELETE <path>/{id}deletes it (answer204).
Passwords and other secrets are never returned. When you send an empty secret, the stored value stays unchanged.
Call groups list their members in members, in ringing order: "phone:<id>" for a phone, "callgroup:<id>" for a contained call group, for example {"name": "Support", "members": ["callgroup:2", "phone:5"]}. A group that would contain itself is refused with 422. The older field member_ids (phone ids only) is still returned and accepted.
Settings
GET /api/v1/settings/{group} returns a settings group, PATCH /api/v1/settings/{group} changes only the fields you send. The groups are system, network, rtp, sip, iax, voicemail, email, features, media, tts, firewall, acme, gui and update.
Applying changes
Changes over the API become pending changes, just like in the web interface:
GET /api/v1/pendinglists the areas with changes that are not applied yet.POST /api/v1/applyapplies them and returns the changed files, the reloaded components and any errors.
Business hours
GET /api/v1/business-hours/{id}/status– whether the business hours are open right now, why (reason:forced,override,special,holidayorschedule), the live mode and the special periods with their switch (active) and whether they apply today.PUT /api/v1/business-hours/{id}/modewith{"mode": "auto"},"open"or"closed"– switches the mode immediately, without apply.PUT /api/v1/business-hours/{id}/special/{special_id}with{"active": true}orfalse– switches a special period on or off immediately, without apply.- The special periods themselves are the
specialslist of the business hours (create and update, then apply).
Audio files
Announcements, music on hold and the voicemail greeting can also be uploaded by scripts, for example from a text-to-speech service:
POST /api/v1/media?kind=<kind>&filename=<name>with the audio as the request body (at most 64 MB, answer201).kindismoh(music on hold),vm_greeting(replaces the voicemail greeting) orivr_prompt(an IVR announcement). The file is converted to 8 kHz mono WAV, like an upload in the web interface; besides WAV, formats such as MP3, OGG and FLAC are accepted.GET /api/v1/medialists the files (optionally?kind=...),GET /api/v1/media/{id}returns one,GET /api/v1/media/{id}/audiodownloads the converted WAV file.DELETE /api/v1/media/{id}deletes a file (answer204).
With a text-to-speech server set up (settings group tts), POST /api/v1/media/tts with {"kind": "ivr_prompt", "name": "welcome", "text": "Welcome ..."} creates an announcement from text (optional voice and speed; answer 201, like an upload). GET /api/v1/tts/voices lists the server’s voices.
An IVR menu uses an uploaded announcement through its id: set "prompt_mode": "upload" and "prompt_media_id": <id> on /api/v1/ivr-menus, then apply. Music on hold and the voicemail greeting are pending changes after an upload as well.
curl -H "Authorization: Bearer phx_..." --data-binary @welcome.wav \
"https://pbx.example.com/api/v1/media?kind=ivr_prompt&filename=welcome.wav"
Click-to-call
POST /api/v1/calls with {"extension": "21", "number": "0441234567"} rings the SIP or IAX phone with that extension. When it is answered, the PBX dials the number from that phone, with the phone’s own outgoing rules and caller ID. The answer is 202 with "status": "ringing". The number may contain digits, *, # and +. The token needs May place calls.
curl -H "Authorization: Bearer phx_..." -H "Content-Type: application/json" \
-d '{"extension": "21", "number": "0441234567"}' https://pbx.example.com/api/v1/calls
AskoziaPBX config.xml
POST /api/v1/legacy/importimports an AskoziaPBXconfig.xmlsent as the request body (at most 10 MB). By default (dry_run=true) it only returns the preview;dry_run=falseimports.mode=replace(the default, a backup is created first) ormode=mergeselects the mode. The answer is the import report as JSON (ok,dry_run,mode,source_version,counts,dropped_sections,items,summary);422when the file has errors, in which case nothing is imported. Apply the changes afterwards.GET /api/v1/legacy/exportreturns the configuration asconfig.xml(application/xml). The file contains all passwords in plain text, so read-only tokens get403, although it is a GET request. Every export is recorded in the audit log.
curl -k -H "Authorization: Bearer phx_..." --data-binary @config.xml \
"https://pbx.example.com/api/v1/legacy/import?dry_run=false&mode=merge"
Status and Prometheus metrics
GET /api/v1/statusreturns system information and the Asterisk state (registrations, channels) as JSON.GET /api/v1/metricsreturns metrics in the Prometheus text format; any valid token works, a read-only one is recommended.
The metrics cover the system (uptime, load, memory, data partition, network traffic), Asterisk (up, start time, active calls and channels), registrations of each phone (phonix_phone_registered) and provider (phonix_provider_up), voicemail messages per mailbox, the TLS certificate expiry and the last ACME request, pending changes and backups. A scrape job:
scrape_configs:
- job_name: phonix
scheme: https
metrics_path: /api/v1/metrics
authorization:
credentials: phx_... # read-only API token
tls_config:
insecure_skip_verify: true # only while the PBX uses its self-signed certificate
static_configs:
- targets: ["pbx.example.com"]
Useful alerts: phonix_provider_up == 0, phonix_asterisk_up == 0, phonix_tls_certificate_expiry_seconds - time() < 14 * 86400.
Errors
| Status | Meaning |
|---|---|
401 | No token, or the token is invalid, disabled or expired. |
403 | The token is read-only (also for the config.xml export), or it may not place calls. |
404 | The object does not exist. |
413 | The uploaded audio file is larger than 64 MB. |
422 | Invalid input. The body contains detail.message and, per field, detail.fields. |
429 | Too many failed authentication attempts; wait a few minutes. |
Error messages of the API are always in English.
MCP for AI assistants
POST /api/mcp is a server for the Model Context Protocol (MCP, streamable HTTP transport). With it, an AI assistant such as Claude can read and change the configuration of the PBX on your behalf. It accepts only bearer tokens. Example for Claude Code:
claude mcp add --transport http phonix https://pbx.example.com/api/mcp \
--header "Authorization: Bearer phx_..."
The tools:
list_*,get_*,create_*,update_*anddelete_*for phones, providers, call groups, conferences, applications, IVR menus, business hours and AMI users.update_*changes only the fields that are given.set_phone_enabled,set_provider_enabled,set_ivr_menu_enabled.get_business_hours_status,set_business_hours_modeandset_business_hours_special(take effect immediately).list_mediaanddelete_mediafor the audio files; upload them with the REST API.create_media_from_textandlist_tts_voicesuse the text-to-speech server.list_settings_groups,get_settings,update_settings.get_status,get_pending_changes,preview_apply(which files and components would change),apply_changes.tail_log– the last lines of theasterisk,system,webormonitorlog (up to 1000). In an OCI container there are no log files, and the tool returns an error.originate_call– click-to-call; only offered to tokens with May place calls.
A read-only token sees only the reading tools. Secrets are never returned. Changes appear in the audit log as <name> (mcp). Give an assistant only the access it needs – a read-only token is enough to answer questions about the configuration or to analyse logs.