sidetone

Advanced

The API

Everything the console does is a request to /v1 with a bearer token. The server also serves its own OpenAPI description at /openapi.json, generated from the code of the version you run, so the fields are never out of date.

The shape of a request

JSON in, JSON out. Every answer is one envelope: success, data and error; errors carry a status, a message that names the field and the reason, and never the value you sent. Lists take limit and offset and carry meta.total. PUT replaces a thing whole; PATCH, where offered, changes the fields you send. A change is live with the answer: configuration is an immutable snapshot swapped under one lock, and every new call reads the current one.

$ curl -sS -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' \
    -d '{"name":"wallboard","scope":"read"}' http://127.0.0.1:8080/v1/tokens
{"success":true,"data":{"id":2,"name":"wallboard","scope":"read","token":"sidetone_…"},"error":null}

Who may call what

  • Admin tokens may do everything.
  • Read-only tokens may GET everything that holds no secret: not the configuration export, not recording or voicemail audio, and of a webhook URL only its host.
  • Users' sessions, from POST /v1/login with an extension and console password, may call only /v1/me…, which takes the extension from the session. A user who is an administrator is raised to admin scope per request.
  • GET /healthz, GET /metrics and POST /v1/login need no token. What desk phones fetch, provisioning files and the phonebook, lives outside /v1 under an address with a secret in it, since a phone cannot send a token.

Resources

PathMethods
/v1/users, /v1/users/{id}GET POST GET PATCH DELETEExtensions: passwords, caller ID, forwarding, voicemail, dialling rules, administrator.
/v1/devices, /v1/devices/{id}GET POST PUT DELETEDesk phones that provision themselves, and softphones. …/password and …/web-password hand out new ones.
/v1/registrationsGET DELETEWho is online; kick one.
/v1/contactsGET POST PUT DELETEThe shared phonebook. /v1/phonebook gives the phones' address; …/address replaces its secret.
/v1/trunks, /v1/routes, /v1/didsGET POST PUT DELETEProviders, where numbers go, where inbound numbers land. A trunk's GET shows its state.
/v1/ring-groups, /v1/queues, /v1/ivr-menus, /v1/schedules, /v1/holiday-setsGET POST PUT DELETEGroups, queues (…/status, …/agents/{user}/paused; /v1/queues/status and /v1/queues/stats for all), menus, business hours, holidays. /v1/holiday-calendars knows the public holidays of some hundred countries.
/v1/audio, /v1/audio/{name}GET PUT DELETEUploaded sounds, 8 kHz mono WAV. …/speech makes one from text.
/v1/voicemail, /v1/recordingsGET PATCH DELETEMessages and recordings; …/audio downloads one.
/v1/calls, /v1/cdrs, /v1/cdrs.csvGET DELETECalls in progress, hang one up; the records, with filters, as JSON or CSV.
/v1/settingsGET PUTEverything server-wide; a field left out keeps its value. …/test-email and …/test-speech try the mail and speech servers.
/v1/tls/certificateGET PUTThe certificate the TLS listeners present, installed live.
/v1/tokens, /v1/bans, /v1/auditGET POST DELETEAPI tokens, banned addresses, who changed what.
/v1/config, /v1/backupsGET PUT, POSTThe whole configuration as one document, secrets included; a database backup now.
/v1/debug/log, /v1/debug/sipGETThe recent log and SIP messages, from memory.
/v1/me, /v1/me/…GET PATCH POST DELETEA signed-in user's own extension, calls, voicemail, password, softphones, contacts and ICE servers.

The exact fields of each, with their limits and the words they take, are in /openapi.json on your own server, which is generated from the code of the version you run.

Webhooks

Two settings push events out rather than wait to be asked: cdr_webhook_url gets a JSON POST for every finished call, and voicemail_webhook_url for every new message. Both are best effort with retries; the records in the server remain the truth. Metrics for Prometheus are at /metrics, named sidetone_…: registrations, calls, media sessions, SIP requests by method, bans, emergency calls.

Scripting it

A shell function is all most people need:

$ api() { curl -sS -H "Authorization: Bearer $TOKEN" -H 'Content-Type: application/json' "$@"; }
$ api localhost:8080/v1/users | jq '.data[] | [.username, .display_name]'
$ api -X PATCH -d '{"dnd":true}' localhost:8080/v1/users/3

For a new office, the fastest route is to set one server up in the console, export its configuration with GET /v1/config, and PUT it to the next.