API reference

The Fonada REST API manages your BYO media-stream configuration and controls live streaming sessions (consult and conference). The real-time media protocol itself runs over WebSocket and is documented in the Audio Streaming overview and Protocol pages.

Base URL

https://api.fonada.example/v1

This value is a placeholder. Fonada provides the production service host during onboarding. Consult and conference examples also use https://<service-host>.

Authentication

All requests require a bearer token. OpenAPI documents the format as JWT:

Authorization: Bearer <token>

Conventions

  • All request and response bodies are application/json.
  • Phone numbers are passed bare; Fonada applies the dialling prefix, operator, and technology from your account configuration.
  • session_id is the live identifier delivered in session_start and returned by GET /sessions.

GET /media-stream

Get current media stream configuration.

  • Requires scope media:manage.
  • Returns the tenant's current BYO media-stream config (URL, codec, sample rates, secret hint).
  • Never returns the plaintext media_secret.
  • Returns 404 when no config is registered for the tenant.
  • Also returns 401, 403, or 503 as listed in Error responses.
{
  "tenant": "acme-voicebot",
  "media_ws_url": "wss://voice.acme.com/stream",
  "codec": "slin16",
  "input_sample_rate": 16000,
  "output_sample_rate": 16000,
  "channels": 1,
  "encoding": "binary",
  "chunk_bytes": 640,
  "secret_hint": "…a1b2"
}

PUT /media-stream

Register or update media stream configuration.

  • Requires scope media:manage.
  • Registers or updates the tenant's BYO media-stream endpoint.
  • The media_secret is write-only and is never returned by any read endpoint.
  • Returns 200 with MediaStreamConfig, or 400 / 401 / 403.
{
  "media_ws_url": "wss://voice.acme.com/stream",
  "codec": "slin16",
  "input_sample_rate": 16000,
  "output_sample_rate": 16000,
  "encoding": "binary",
  "chunk_bytes": 640,
  "media_secret": "s3cr3t-rotate-me"
}

GET /sessions

Returns all live streaming sessions for the tenant, each identified by its session_id. Use this to discover the id needed by the consult and conference endpoints.

[
  {
    "session_id": "1711234567.42",
    "customer_phone": "919876543210",
    "direction": "inbound",
    "started_at": "2026-08-18T09:12:04Z",
    "conferenceNumbers": []
  }
]

GET /sessions/{session_id}

Returns session detail, including conferenceNumbers. Returns 401 if unauthorised and 404 if the session is not found.

{
  "session_id": "1711234567.42",
  "customer_phone": "919876543210",
  "direction": "inbound",
  "started_at": "2026-08-18T09:12:04Z",
  "conferenceNumbers": ["7042009848"]
}

POST /sessions/{session_id}/consult

Puts the caller on hold and dials a second party, bridging them privately with the bot. Synchronous — blocks until the party answers, the dial fails, or the timeout elapses (default 20s + 5s margin). Set your HTTP read-timeout to at least 30 seconds.

Request body: calledParty (bare number), optional callerId. Full field tables, status codes, and curl examples are on Consult & conference.

{
  "sessionId": "1711234567.42",
  "consultId": "consult-1711234567.42",
  "status": "answered",
  "dialStatus": "ANSWER"
}

POST /sessions/{session_id}/conference

Adds a party to, or removes a party from, the live call. Everyone in the bridge hears everyone. Switched by the action field (add or delete). Required fields: action, number. Optional callerId on add.

Returns 200, 400, 401, 404, or 409. See Consult & conference for complete request and response tables.

Schemas

MediaStreamConfig

FieldTypeNotes
tenantstringTenant identifier.
media_ws_urluri stringYour WebSocket endpoint.
codecstringExample slin16 (Asterisk-style name for PCM16).
input_sample_rateinteger8000 or 16000.
output_sample_rateinteger8000 or 16000.
channelsintegerAlways 1.
encodingstringbinary or base64.
chunk_bytesintegerExample 640.
secret_hintstringMasked hint only. Never the plaintext media_secret.

MediaStreamUpsert

FieldTypeNotes
media_ws_urluri stringRequired.
codecstringExample slin16.
input_sample_rateinteger8000 or 16000.
output_sample_rateinteger8000 or 16000.
encodingstringbinary or base64.
chunk_bytesintegerExample 640.
media_secretstringWrite-only. Never returned by any read endpoint.

Session

FieldTypeNotes
session_idstringLive id from session_start.
customer_phonestringEnd-user number.
directionstringinbound or outbound.
started_atdate-timeISO timestamp.
conferenceNumbersstring[]Current conference members.

ConsultRequest

FieldTypeNotes
calledPartystringBare number of the second party. Fonada applies prefix, operator, and technology.
callerIdstringBare Caller ID to present. Falls back to the configured default.

ConsultResult

FieldTypeNotes
sessionIdstringThe session id.
consultIdstringconsult-<sessionId>.
statusstringanswered, failed, or timeout.
dialStatusstringANSWER, NOANSWER, BUSY, CONGESTION, or CHANUNAVAIL.
causeintegerQ.850 cause; present only when status=failed.
causeTextstringPresent only when status=failed.

ConferenceRequest

FieldTypeNotes
actionstringRequired. add or delete.
numberstringRequired. Bare number.
callerIdstringadd only.

ConferenceResult

FieldTypeNotes
sessionIdstringThe session id.
numberstringThe bare number.
channelIdstringconf-<sessionId>-<number>.
statusstringanswered, failed, or timeout.
dialStatusstringGuide values: ANSWER, NOANSWER, BUSY, CONGESTION, CHANUNAVAIL. OpenAPI lists ANSWER, NOANSWER, BUSY.

Error responses

Error bodies use error and message string fields.

CodeNameMeaning
400Bad RequestMalformed request.
401UnauthorizedMissing or invalid credentials.
403ForbiddenInsufficient scope (for example media:manage).
404Not FoundResource not found. GET /media-stream returns 404 when no config is registered.
409ConflictConflicting state (conference add).
500Server ErrorCould not place the call.
503UnavailableService temporarily unavailable (GET /media-stream).