VitrinaAPI

Clinic professionals

Who sees patients at the clinic, in which speciality and with what default block — the id the agenda uses as a lane.

Beta
This may change at any time, with a changelog entry and a notice to recent callers — see versioning.

Download the full API pública projection: openapi.json.

List services and their prices explains this resource in prose, with runnable examples.

MethodPathWhat it does
GET/clinic/professionalsList the clinic's professionals
POST/clinic/professionalsCreate 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/specialtiesList the clinic's specialties
POST/clinic/specialtiesCreate 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.

ParameterInTypeRequiredConstraints
searchquerystringnomín. 2, máx. 120
especialidadquerystringnomín. 1, máx. 160
activequerytrue \falseno
sortquerynombre \especialidad \intervalo \
dirqueryasc \descno
pagequeryintegerno≥ 1, por defecto 1
limitqueryintegerno≥ 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

FieldTypeRequiredConstraints
nombrestringyesmín. 1, máx. 160
apellidosstring | null—máx. 160
rutstring | null—máx. 20
emailstring | null—máx. 160
phonestring | null—máx. 40
especialidadstring | null—máx. 160
especialidades_secundariasstring[]—
cargostring | null—máx. 120
registrostring | null—máx. 80
sexostring | null—máx. 40
birthdatestring | null—patrón ^\d{4}-\d{2}-\d{2}$
direccionstring | null—máx. 240
agenda_onlineboolean—
intervalo_minutesinteger | null—≥ 1, ≤ 600
scheduleobject | null—
descriptionstring | 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.

ParameterInTypeRequiredConstraints
idpathuuidyes
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.

ParameterInTypeRequiredConstraints
idpathuuidyes
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.

ParameterInTypeRequiredConstraints
idpathuuidyes

Body

FieldTypeRequiredConstraints
nombrestring—mín. 1, máx. 160
apellidosstring | null—máx. 160
rutstring | null—máx. 20
emailstring | null—máx. 160
phonestring | null—máx. 40
especialidadstring | null—máx. 160
especialidades_secundariasstring[]—
cargostring | null—máx. 120
registrostring | null—máx. 80
sexostring | null—máx. 40
birthdatestring | null—patrón ^\d{4}-\d{2}-\d{2}$
direccionstring | null—máx. 240
agenda_onlineboolean—
intervalo_minutesinteger | null—≥ 1, ≤ 600
scheduleobject | null—
descriptionstring | null—máx. 2000
activeboolean—
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.

ParameterInTypeRequiredConstraints
enabledquerytrue \falseno
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

FieldTypeRequiredConstraints
nombrestringyesmí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.

ParameterInTypeRequiredConstraints
idpathuuidyes
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.

ParameterInTypeRequiredConstraints
idpathuuidyes

Body

FieldTypeRequiredConstraints
enabledbooleanyes
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

On this page