Clinic professionals
Who sees patients at the clinic, in which speciality and with what default block — the id the agenda uses as a lane.
Download the full API pública projection: openapi.json.
List services and their prices explains this resource in prose, with runnable examples.
| Method | Path | What it does |
|---|---|---|
GET | /clinic/professionals | List the clinic's professionals |
POST | /clinic/professionals | Create a native professional |
DELETE | /clinic/professionals/{id} | Delete a native professional |
GET | /clinic/professionals/{id} | Get one clinic professional |
PATCH | /clinic/professionals/{id} | Update a professional |
GET | /clinic/specialties | List the clinic's specialties |
POST | /clinic/specialties | Create a specialty (find-or-create, native only) |
DELETE | /clinic/specialties/{id} | Delete a specialty |
PATCH | /clinic/specialties/{id} | Enable/disable a specialty |
GET /clinic/professionals
List the clinic's professionals
search (min 2 chars) matches the name accent-insensitively OR the primary/secondary specialties. active is OPTIONAL and omitting it returns EVERY row, active and retired — a professional who left still names mirrored citas. Sorted by sort/dir (default: display name asc; also especialidad, intervalo, synced_at). schedule is null when the weekly-hours read has not landed, which does NOT mean the professional works no days.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
search | query | string | no | mín. 2, máx. 120 |
especialidad | query | string | no | mín. 1, máx. 160 |
active | query | true \ | false | no |
sort | query | nombre \ | especialidad \ | intervalo \ |
dir | query | asc \ | desc | no |
page | query | integer | no | ≥ 1, por defecto 1 |
limit | query | integer | no | ≥ 1, ≤ 200, por defecto 50 |
curl https://api.vitrinadev.com/api/v1/clinic/professionals \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"data": [
{
"id": "18342d1b-0000-4000-8000-000000000001",
"source": "native",
"external_id": null,
"nombre": "Ana",
"apellidos": "Rojas Vidal",
"rut": "12.345.678-5",
"email": "[email protected]",
"phone": null,
"especialidad": "Ortodoncia",
"especialidades_secundarias": [],
"cargo": null,
"registro": "SIS 123456",
"sexo": null,
"birthdate": null,
"direccion": null,
"agenda_online": true,
"intervalo_minutes": 30,
"active": true,
"description": null,
"schedule": null,
"synced_at": null,
"created_at": "2026-09-22T22:21:14.494Z",
"updated_at": "2026-09-22T22:21:14.494Z"
}
],
"total": 1,
"page": 1,
"limit": 50
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/professionals
Create a native professional
Create one of the clinic's OWN (native) professionals — source is 'native', active is true. 409 not_native_source when the tenant's clinic source is not 'native' (activate native booking first). schedule is the weekly-hours editor payload (mon..sun → [{inicio,fin}], HH:MM).
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
nombre | string | yes | mín. 1, máx. 160 |
apellidos | string | null | — | máx. 160 |
rut | string | null | — | máx. 20 |
email | string | null | — | máx. 160 |
phone | string | null | — | máx. 40 |
especialidad | string | null | — | máx. 160 |
especialidades_secundarias | string[] | — | |
cargo | string | null | — | máx. 120 |
registro | string | null | — | máx. 80 |
sexo | string | null | — | máx. 40 |
birthdate | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
direccion | string | null | — | máx. 240 |
agenda_online | boolean | — | |
intervalo_minutes | integer | null | — | ≥ 1, ≤ 600 |
schedule | object | null | — | |
description | string | null | — | máx. 2000 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/professionals \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"nombre": "Ana",
"apellidos": "Rojas Vidal",
"rut": "12.345.678-5",
"email": "[email protected]",
"especialidad": "Ortodoncia",
"registro": "SIS 123456",
"agenda_online": true,
"intervalo_minutes": 30
}'Example response (201)
{
"data": {
"id": "18342d1b-0000-4000-8000-000000000001",
"source": "native",
"external_id": null,
"nombre": "Ana",
"apellidos": "Rojas Vidal",
"rut": "12.345.678-5",
"email": "[email protected]",
"phone": null,
"especialidad": "Ortodoncia",
"especialidades_secundarias": [],
"cargo": null,
"registro": "SIS 123456",
"sexo": null,
"birthdate": null,
"direccion": null,
"agenda_online": true,
"intervalo_minutes": 30,
"active": true,
"description": null,
"schedule": null,
"synced_at": null,
"created_at": "2026-09-22T22:21:14.494Z",
"updated_at": "2026-09-22T22:21:14.494Z"
}
}Answers: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /clinic/professionals/{id}
Delete a native professional
Native → hard-deleted. Synced (vendor) → 400 cannot_delete_synced; deactivate it with PATCH active:false instead (mirrored citas still name it).
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
curl -X DELETE https://api.vitrinadev.com/api/v1/clinic/professionals/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Answers: 204 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/professionals/{id}
Get one clinic professional
The list view plus the raw vendor payload (data) and citas_next_7d — the live (pending/confirmed) citas this professional holds over the next seven days, counted off the mirrored shadow rows.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
curl https://api.vitrinadev.com/api/v1/clinic/professionals/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"id": "18342d1b-0000-4000-8000-000000000001",
"source": "native",
"external_id": null,
"nombre": "Ana",
"apellidos": "Rojas Vidal",
"rut": "12.345.678-5",
"email": "[email protected]",
"phone": null,
"especialidad": "Ortodoncia",
"especialidades_secundarias": [],
"cargo": null,
"registro": "SIS 123456",
"sexo": null,
"birthdate": null,
"direccion": null,
"agenda_online": true,
"intervalo_minutes": 30,
"active": true,
"description": null,
"schedule": null,
"synced_at": null,
"created_at": "2026-09-22T22:21:14.494Z",
"updated_at": "2026-09-22T22:21:14.494Z",
"data": {},
"citas_next_7d": 0
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /clinic/professionals/{id}
Update a professional
Edit a professional (covers activar/desactivar via active). description is Vitrina-owned and editable on ANY source (native or synced mirror); every OTHER field returns 400 not_editable on a synced (non-native) row — those are managed in the clinic system, not Vitrina.
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
nombre | string | — | mín. 1, máx. 160 |
apellidos | string | null | — | máx. 160 |
rut | string | null | — | máx. 20 |
email | string | null | — | máx. 160 |
phone | string | null | — | máx. 40 |
especialidad | string | null | — | máx. 160 |
especialidades_secundarias | string[] | — | |
cargo | string | null | — | máx. 120 |
registro | string | null | — | máx. 80 |
sexo | string | null | — | máx. 40 |
birthdate | string | null | — | patrón ^\d{4}-\d{2}-\d{2}$ |
direccion | string | null | — | máx. 240 |
agenda_online | boolean | — | |
intervalo_minutes | integer | null | — | ≥ 1, ≤ 600 |
schedule | object | null | — | |
description | string | null | — | máx. 2000 |
active | boolean | — |
curl -X PATCH https://api.vitrinadev.com/api/v1/clinic/professionals/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"cargo": "Ortodoncista",
"especialidades_secundarias": [
"Odontopediatría"
]
}'Example response (200)
{
"data": {
"id": "18342d1b-0000-4000-8000-000000000001",
"source": "native",
"external_id": null,
"nombre": "Ana",
"apellidos": "Rojas Vidal",
"rut": "12.345.678-5",
"email": "[email protected]",
"phone": null,
"especialidad": "Ortodoncia",
"especialidades_secundarias": [
"Odontopediatría"
],
"cargo": "Ortodoncista",
"registro": "SIS 123456",
"sexo": null,
"birthdate": null,
"direccion": null,
"agenda_online": true,
"intervalo_minutes": 30,
"active": true,
"description": null,
"schedule": null,
"synced_at": null,
"created_at": "2026-09-22T22:21:14.494Z",
"updated_at": "2026-09-22T22:21:14.527Z"
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/specialties
List the clinic's specialties
List the clinic's specialties
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
enabled | query | true \ | false | no |
curl https://api.vitrinadev.com/api/v1/clinic/specialties \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"id": "69762225-0000-4000-8000-000000000001",
"source": "native",
"external_id": null,
"nombre": "Ortodoncia",
"enabled": true,
"is_editable": true,
"synced_at": null,
"created_at": "2026-09-22T22:21:14.433Z",
"updated_at": "2026-09-22T22:21:14.433Z"
}
]
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/specialties
Create a specialty (find-or-create, native only)
Create a specialty (find-or-create, native only)
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
nombre | string | yes | mín. 1, máx. 160 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/specialties \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"nombre": "Ortodoncia"
}'Example response (201)
{
"data": {
"id": "69762225-0000-4000-8000-000000000001",
"source": "native",
"external_id": null,
"nombre": "Ortodoncia",
"enabled": true,
"is_editable": true,
"synced_at": null,
"created_at": "2026-09-22T22:21:14.433Z",
"updated_at": "2026-09-22T22:21:14.433Z"
}
}Answers: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /clinic/specialties/{id}
Delete a specialty
Delete a specialty
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
curl -X DELETE https://api.vitrinadev.com/api/v1/clinic/specialties/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Answers: 204 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /clinic/specialties/{id}
Enable/disable a specialty
Enable/disable a specialty
Connected apps: every patient and contact in the response is a Seudónimo de paciente — initials plus a stable number, "M.F. · #1001" — unless the clinic allowed patient names, with RUT, phone and email masked in free text and meta.patient_privacy saying so. Clinical alerts (flags) are withheld in both modes, and a non-JSON body (an export, a file) is refused with 403 CONNECTED_APP_SENSITIVE_DATA.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
enabled | boolean | yes |
curl -X PATCH https://api.vitrinadev.com/api/v1/clinic/specialties/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": true
}'Example response (200)
{
"data": {
"id": "69762225-0000-4000-8000-000000000001",
"source": "native",
"external_id": null,
"nombre": "Ortodoncia",
"enabled": true,
"is_editable": true,
"synced_at": null,
"created_at": "2026-09-22T22:21:14.433Z",
"updated_at": "2026-09-22T22:21:14.447Z"
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429