Workspace detail
The whole clinic in one call — locations, practitioners, fees, and their public profiles.
GET /v2/workspacesThe call you make first. It returns the clinic's locations, the practitioners at each, what they charge, which booking system they run, and the public profiles that carry their names and photographs — composed from two upstream sources so you do not have to fetch a profile per doctor.
Every id you need to book comes from here: addresses[].id is addressId,
addresses[].doctors[].id is doctorId.
No OTP. The workspace comes from your key.
Query parameters
| Name | Type | Required | Description |
|---|---|---|---|
patientCountryCode | string | No | Where the patient is — a dial code (+91), an ISO2 code (IN) or a country name. Decides, per location, whether they are quoted domestic or international prices. |
Omitting patientCountryCode leaves international null on every address, and
the international price rows absent. It narrows pricing only — the profile
bundle is unaffected.
Try it
/v2/workspacesThe best first call — nothing is required, and it proves the whole chain.
Query
GET /v2/workspaceshttps://api.medos.oneUse a dedicated test key, and put your browser's address on its allowlist
A Developer API key authenticates on its own, so it only works from the addresses registered against it — and this page calls from your browser, not your servers. Unless your own public address is on the list you get a 403 naming it, which is the allowlist doing its job. Your browser may also reach us over IPv6 even when your server does not, so the address in the error is often not the one you expected. The key here is kept in memory only and never written to storage, but create a test key for it and deactivate that key when you are done.
Request
curl -sG "https://api.medos.one/v2/workspaces" \
-H "x-api-key: $MEDOS_API_KEY" \
--data-urlencode "patientCountryCode=IN"Response
{
"workspaceId": 1,
"onlineBookingEnabled": true,
"onlinePaymentEnabled": true,
"onlinePaymentProvider": "RAZORPAY",
"addresses": [
{
"id": 1,
"fullAddress": "42 Church Street, Bengaluru 560001",
"city": "Bengaluru",
"state": "Karnataka",
"country": "India",
"international": false,
"doctors": [
{
"id": 4,
"specialization": "Physiotherapy",
"appointmentSystemType": "SCHEDULED",
"consultationFees": [
{ "consultationMode": "OFFLINE", "currency": "INR", "amount": 500, "isInternational": false }
],
"qmsConsultationCharges": [],
"appointmentTypeAndPermission": {
"allowOnline": false,
"allowOffline": true,
"allowCancellation": true,
"allowRescheduling": true,
"cancellationAllowedBeforeInHours": 4,
"canHostOnline": true
},
"publicProfile": {
"profileId": 4,
"name": "Dr. Meera Rao",
"specialization": "Physiotherapy",
"qualification": "MPT (Ortho)",
"experience": 11,
"profileImageUrl": "https://…/meera.jpg",
"published": true,
"slug": null,
"gallery": null,
"faqs": null,
"seo": null
}
}
]
}
],
"sessionPacks": [],
"publicProfile": {
"wpp": { "profileId": 1, "name": "Church Street Physiotherapy" },
"p": []
}
}| Field | Meaning |
|---|---|
addresses[].id | The addressId every booking route takes. |
addresses[].international | Whether this location quotes the patient from its international price list, given the patientCountryCode you sent. |
doctors[].id | The doctorId every booking route takes. |
doctors[].appointmentSystemType | SCHEDULED or QMS — which booking flow this doctor uses. Read it before deciding whether to fetch slots or shifts. |
doctors[].consultationFees[] | Fee per consultation mode and currency, with isInternational distinguishing the two price lists. |
doctors[].appointmentTypeAndPermission | What the clinic allows: which modes, whether patients may cancel or reschedule, and the cancellation cut-off in hours. |
doctors[].appointmentTypeAndPermission.canHostOnline | Whether this practitioner can get a video link for an online booking. On Zoom clinics each practitioner connects their own account, so this can be false while onlineBookingEnabled is true. |
doctors[].publicProfile | The practitioner's profile, joined for you. null when they have no profile, only an unpublished draft, or a deactivated membership. |
publicProfile.wpp | The workspace's own public profile. null when unset. |
publicProfile.p[] | Every published practitioner profile, unjoined — the same records already attached to the doctors. |
onlineBookingEnabled | Whether the clinic can host video consultations at all — its Google account is connected, at least one practitioner has connected Zoom, or it uses the built-in video. |
onlinePaymentEnabled | Whether reserve-slot can mint a checkout at all. |
When to offer an online consultation
Offer the Online mode for a doctor only when onlineBookingEnabled,
appointmentTypeAndPermission.allowOnline and
appointmentTypeAndPermission.canHostOnline are all true — the same rule the clinic's own check-in page follows. An
online booking for a practitioner who cannot host is rejected.
The doctor's name lives on the profile
doctors[] carries ids, fees and permissions — not names. Render from
doctors[].publicProfile.name, and have a fallback for the null case: a
practitioner who takes bookings but has no published profile is a normal state,
not an error.
Profiles here are thin
slug, gallery, faqs, socialLinks, workHistory, seo, videoUrl,
treatmentPhilosophy, whatToExpect and updatedAt are always null in
this payload — the bundle is built without the enrichment step. They come back
populated from
GET /v1/public-profiles/:profileId
and nowhere else.
Common failures
| Status | Cause |
|---|---|
4xx/5xx | Either half failing fails the whole call, with the upstream status and body passed through unchanged. There is no partial response. |
Cache it, but not for long
Locations, doctors and fees change rarely; profile edits and a doctor being deactivated are what move. Re-reading per booking session is usually right; per request is wasteful.