Switchboard (PBX) Integration Guide
Switchboard (PBX) Integration Guide
This guide is for third-party phone switchboard (PBX) providers — e.g. virtual operators running Yeastar P-Series — who want to connect their call flows to Medevio. The integration covers two areas:
-
Call routing checks — decide where to route a caller based on the clinic's state (open, on vacation, caller already has an active request).
-
Call hand-off — after the call ends, send Medevio the call metadata and the voicemail recording. Medevio transcribes the message and creates a patient request for the clinic.
Medevio does not host any middleware: your PBX (or your integration layer) calls the endpoints below directly.
Basics
-
Base URL:
https://api.medevio.cz/external/v1/clinics/{clinicSlug}/switchboard -
Method: all endpoints are
POST -
Content type:
application/jsonrequests and responses -
Clinic identification: the clinic slug — the stable identifier of the clinic in Medevio — is part of the URL path, same as in the rest of the Medevio API. You receive the slugs (and all connectivity details) during onboarding with Medevio.
-
Success is always HTTP 200. Boolean answers are returned in the body (there is no meaning encoded in non-200 status codes). Errors use standard status codes — see Error handling below.
-
Machine-readable reference: the same endpoints are documented in the Medevio API reference under the Switchboards tag.
Authentication
All endpoints require a Personal Access Token issued by Medevio during onboarding, sent with every request:
Authorization: Bearer <token>
The token is bound to a set of clinics and to scopes: the three check endpoints require the Read scope, recording-complete requires the Write scope. A missing or invalid token returns 401; a token that lacks the required scope or has no access to the clinic in the URL returns 403. One token can cover all clinics you operate.
Note on field names: the check endpoints use camelCase body fields, while recording-complete uses PascalCase fields CallSid, RecordingUrl, …) for historical compatibility with Twilio webhooks. Follow the examples exactly.
Typical call flow
Caller dials the clinic number
│
├─ POST /is-clinic-opened → closed? play after-hours message
├─ POST /is-on-vacation → on vacation / public holiday? play vacation message
├─ POST /has-active-request → caller already has an open request? tell them, skip voicemail
│
├─ Caller records a voicemail (or hangs up)
│
└─ POST /recording-complete → Medevio ingests the call + recording,
transcribes it and creates a patient request
Which checks you call (and in what order) is up to your flow — each one is independent.
Endpoints
1. POST …/switchboard/is-clinic-opened
Is the clinic currently inside its office hours? Office hours support odd/even week schedules and are evaluated in the clinic's timezone. No request body is needed.
// POST https://api.medevio.cz/external/v1/clinics/my-clinic/switchboard/is-clinic-opened
// Response (200)
{ "isOpen": true }
2. POST …/switchboard/is-on-vacation
Is the clinic on vacation right now? Returns true when the clinic has an active vacation that applies to the switchboard, or when today is a public holiday in the clinic's country (unless all relevant calendars are configured to ignore holidays).
calendarIds is optional — when provided, only vacations in those calendars are considered; otherwise all clinic calendars are checked.
// Request (send {} to check all clinic calendars)
{
"calendarIds": ["4c5a1f4e-6a30-4d9b-9df7-0a4f8a1a2b3c"]
}
// Response (200)
{ "isOnVacation": false }
3. POST …/switchboard/has-active-request
Does the caller already have an open (not yet resolved) patient request in the clinic? Useful as a switch in the flow — e.g. to tell the caller their request is being processed instead of recording another voicemail.
Provide at least one of callFrom (caller's phone number) or patientId (Medevio patient UUID). The phone number is matched against the clinic's patient records.
// Request
{
"callFrom": "+420777123456"
}
// Response (200)
{ "hasActiveRequest": false }
4. POST …/switchboard/recording-complete
Call this once the call has ended — with or without a recording. Medevio creates a call record, downloads and transcribes the recording, matches the caller to a patient (or creates a new patient record from the phone number) and creates a patient request for the clinic.
|
Field |
Type |
Required |
Description |
|---|---|---|---|
|
|
string |
yes |
Unique ID of the call in your system. Used for deduplication — retries with the same |
|
|
string |
yes |
Caller's phone number, ideally E.164 ( |
|
|
string |
yes |
The dialed number (the clinic's line). |
|
|
string |
no |
Final call status in your system (e.g. |
|
|
boolean |
no |
Informational only — processing is driven by whether |
|
|
string |
no |
Public https download URL of the recording ( |
|
|
string |
no |
Stable identifier of the recording file in your system (e.g. the Yeastar file name). See Recording lifetime. |
|
|
string |
no |
Identifies your platform, e.g. |
|
|
string |
no |
Free-form payload stored with the call (e.g. flow variables). |
// Request
{
"CallSid": "1651057476.362",
"CallFrom": "+420777123456",
"CallTo": "+420228810143",
"Status": "ANSWERED",
"HasRecording": true,
"RecordingUrl": "https://pbx.example.com/api/download/20260416-143000-call-362.wav?access_token=abc",
"RecordingSid": "20260416-143000-call-362.wav",
"Source": "FAYN operator"
}
// Response (200)
{ "success": true }
What happens next in Medevio:
-
Recording with an intelligible message → the message is transcribed and a voice message patient request is created for the clinic, containing the caller's number and the transcript. The recording is playable from the request detail.
-
Recording with an empty/unintelligible message → a missed call request is created instead. (Clinics may opt out of these — then nothing is created.)
-
No
RecordingUrl→ only the call record is stored. -
Transcription runs asynchronously right after the webhook — the
RecordingUrlmust therefore be valid at least a few minutes after you send it.
Recording lifetime and re-fetching
Doctors can play the recording from the patient request at any later time, but many PBX platforms serve recordings via short-lived URLs (Yeastar download links embed an access token valid for ~30 minutes).
Medevio never copies recordings to its own storage. Instead, when a doctor opens the request after the original URL has expired, Medevio requests a fresh download URL from your platform's API, using:
-
the
RecordingSidyou sent inrecording-complete(falling back to the file name fromRecordingUrl), and -
API credentials for the clinic's PBX tenant that you hand over during onboarding (for Yeastar: OpenAPI base URL +
get_tokenusername and password).
If the fresh URL cannot be obtained — credentials not provided, or your platform has already deleted the recording due to retention limits — the doctor sees "The recording is no longer available" instead of the player. The transcript always stays available since it is produced at ingest time.
Yeastar / FAYN specifics
-
Set
Sourceto a value containingYeastarorFAYN— this switches Medevio to the Yeastar re-fetch strategy for expired recording URLs. -
Send the recording file name as
RecordingSid(e.g.20220427190445-1651057476.362-2005-2002-Internal.wav) — it is the stable reference used with the Yeastarrecording/downloadOpenAPI call. -
Provide Medevio with the P-Series OpenAPI access per clinic tenant: base URL (e.g.
https://<tenant>.ras.yeastar.com) and API username + password for the token exchange (get_token, download a recording file). -
Mind Yeastar's recording retention: recordings are auto-deleted when storage fills up or after a configured age. After deletion, only the transcript remains available in Medevio.
Error handling & testing checklist
-
Errors respond with standard status codes and the body
{ "error": "...", "code": "..." }:-
400— malformed payload (validation failure; e.g. a non-https or internalRecordingUrl), -
401— missing or invalid token, -
403— token lacks the required scope or has no access to the clinic, -
404— unknownclinicSlug, -
409— theCallSidis already used by another clinic, -
5xx— internal error, safe to retry.
-
-
recording-completeis idempotent perCallSid— safe to retry. -
Before going live, verify with Medevio on the staging environment:
-
all three checks respond for your test clinic with your token,
-
a call with a recording produces a voice-message request with a transcript and a playable recording,
-
a call with an empty recording produces a missed-call request,
-
an expired recording URL is re-fetched through your API (or correctly reported as unavailable).
-