Clinic services
What the clinic performs: duration, list price, consent requirements and who may perform each service.
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/service-categories | List the clinic's service categories |
POST | /clinic/service-categories | Create a service category (find-or-create, native only) |
DELETE | /clinic/service-categories/{id} | Delete a service category |
PATCH | /clinic/service-categories/{id} | Enable/disable a service category |
GET | /clinic/services | List the clinic's services |
POST | /clinic/services | Create a native service |
DELETE | /clinic/services/{id} | Delete a native service |
PATCH | /clinic/services/{id} | Edit a native service (or activar/desactivar) |
GET | /clinic/services/{id}/professionals | Who may perform a prestación |
PUT | /clinic/services/{id}/professionals | Set who may perform a prestación |
GET /clinic/service-categories
List the clinic's service categories
List the clinic's service categories
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/service-categories \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"id": "795cf9e4-0000-4000-8000-000000000001",
"source": "native",
"nombre": "Ortodoncia",
"enabled": true,
"created_at": "2026-09-22T22:21:14.461Z",
"updated_at": "2026-09-22T22:21:14.461Z"
}
]
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/service-categories
Create a service category (find-or-create, native only)
Create a service category (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. 120 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/service-categories \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"nombre": "Ortodoncia"
}'Example response (201)
{
"data": {
"id": "795cf9e4-0000-4000-8000-000000000001",
"source": "native",
"nombre": "Ortodoncia",
"enabled": true,
"created_at": "2026-09-22T22:21:14.461Z",
"updated_at": "2026-09-22T22:21:14.461Z"
}
}Answers: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /clinic/service-categories/{id}
Delete a service category
Delete a service category
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/service-categories/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Answers: 204 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /clinic/service-categories/{id}
Enable/disable a service category
Enable/disable a service category
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/service-categories/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"enabled": true
}'Example response (200)
{
"data": {
"id": "795cf9e4-0000-4000-8000-000000000001",
"source": "native",
"nombre": "Ortodoncia",
"enabled": true,
"created_at": "2026-09-22T22:21:14.461Z",
"updated_at": "2026-09-22T22:21:14.476Z"
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/services
List the clinic's services
The clinic's price list. search (min 2 chars) matches nombre, código or categoría accent-insensitively. active is OPTIONAL and omitting it returns every row. precio is the vendor LIST price before previsión/convenio — it is deliberately never shown to the AI agent. is_entry filters entry prestaciones, tri-state: true = entry (evaluación / diagnóstico), false = CONFIRMED treatment rows only, unclassified = nobody has said yet (is_entry IS NULL); omitted = every row.
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 |
active | query | true \ | false | no |
review_state | query | pending \ | stale \ | draft \ |
is_entry | query | true \ | false \ | unclassified |
sort | query | nombre \ | codigo \ | categoria \ |
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/services \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"data": [
{
"id": "4cf5bc59-0000-4000-8000-000000000001",
"source": "native",
"external_id": null,
"nombre": "Control de ortodoncia",
"codigo": "ORT-CTRL",
"categoria": "Ortodoncia",
"tipo": null,
"precio": 25000,
"arancel": null,
"duration_minutes": 30,
"vendor_duration_minutes": null,
"review_state": "draft",
"reviewed_at": null,
"reviewed_by": null,
"is_telehealth": false,
"online_bookable": true,
"requires_consent_template_id": null,
"eligibility_min_age_years": null,
"eligibility_max_age_years": null,
"eligibility_sexo": null,
"eligibility_previsiones": null,
"active": true,
"synced_at": null
},
{
"id": "4cf5bc59-0000-4000-8000-000000000002",
"source": "native",
"external_id": null,
"nombre": "Limpieza dental",
"codigo": null,
"categoria": "Ortodoncia",
"tipo": null,
"precio": 35000,
"arancel": null,
"duration_minutes": 45,
"vendor_duration_minutes": null,
"review_state": "draft",
"reviewed_at": null,
"reviewed_by": null,
"is_telehealth": false,
"online_bookable": false,
"requires_consent_template_id": null,
"eligibility_min_age_years": null,
"eligibility_max_age_years": null,
"eligibility_sexo": null,
"eligibility_previsiones": null,
"active": true,
"synced_at": null
}
],
"total": 2,
"page": 1,
"limit": 50
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/services
Create a native service
Create a native service
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. 200 |
codigo | string | null | — | máx. 60 |
categoria | string | null | — | máx. 120 |
tipo | string | null | — | máx. 120 |
precio | integer | null | — | ≥ 0, ≤ 1000000000 |
duration_minutes | integer | null | — | ≥ 1, ≤ 1440 |
active | boolean | — | |
is_telehealth | boolean | — | |
online_bookable | boolean | — | |
is_entry | boolean | null | — | |
requires_consent_template_id | string | null | — | |
eligibility_min_age_years | integer | null | — | ≥ 0, ≤ 120 |
eligibility_max_age_years | integer | null | — | ≥ 0, ≤ 120 |
eligibility_sexo | F \ | M \ | otro |
eligibility_previsiones | array | null | — |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/services \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"nombre": "Control de ortodoncia",
"codigo": "ORT-CTRL",
"categoria": "Ortodoncia",
"precio": 25000,
"duration_minutes": 30,
"online_bookable": true
}'Example response (201)
{
"data": {
"id": "4cf5bc59-0000-4000-8000-000000000001",
"source": "native",
"external_id": null,
"nombre": "Control de ortodoncia",
"codigo": "ORT-CTRL",
"categoria": "Ortodoncia",
"tipo": null,
"precio": 25000,
"arancel": null,
"duration_minutes": 30,
"vendor_duration_minutes": null,
"review_state": "draft",
"reviewed_at": null,
"reviewed_by": null,
"is_telehealth": false,
"online_bookable": true,
"requires_consent_template_id": null,
"eligibility_min_age_years": null,
"eligibility_max_age_years": null,
"eligibility_sexo": null,
"eligibility_previsiones": null,
"active": true,
"synced_at": null
}
}Answers: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /clinic/services/{id}
Delete a native service
Delete a native service
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/services/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Answers: 204 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /clinic/services/{id}
Edit a native service (or activar/desactivar)
Edit a native service (or activar/desactivar)
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. 200 |
codigo | string | null | — | máx. 60 |
categoria | string | null | — | máx. 120 |
tipo | string | null | — | máx. 120 |
precio | integer | null | — | ≥ 0, ≤ 1000000000 |
duration_minutes | integer | null | — | ≥ 1, ≤ 1440 |
active | boolean | — | |
is_telehealth | boolean | — | |
online_bookable | boolean | — | |
is_entry | boolean | null | — | |
requires_consent_template_id | string | null | — | |
eligibility_min_age_years | integer | null | — | ≥ 0, ≤ 120 |
eligibility_max_age_years | integer | null | — | ≥ 0, ≤ 120 |
eligibility_sexo | F \ | M \ | otro |
eligibility_previsiones | array | null | — |
curl -X PATCH https://api.vitrinadev.com/api/v1/clinic/services/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"precio": 28000
}'Example response (200)
{
"data": {
"id": "4cf5bc59-0000-4000-8000-000000000001",
"source": "native",
"external_id": null,
"nombre": "Control de ortodoncia",
"codigo": "ORT-CTRL",
"categoria": "Ortodoncia",
"tipo": null,
"precio": 28000,
"arancel": null,
"duration_minutes": 30,
"vendor_duration_minutes": null,
"review_state": "draft",
"reviewed_at": null,
"reviewed_by": null,
"is_telehealth": false,
"online_bookable": true,
"requires_consent_template_id": null,
"eligibility_min_age_years": null,
"eligibility_max_age_years": null,
"eligibility_sexo": null,
"eligibility_previsiones": null,
"active": true,
"synced_at": null
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/services/{id}/professionals
Who may perform a prestación
The eligibility set, with each professional’s optional duration and price override. NO ROWS means "anyone may" — never "nobody may".
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.
curl https://api.vitrinadev.com/api/v1/clinic/services/<id>/professionals \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": [
{
"id": "18342d1b-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"clinic_service_id": "4cf5bc59-0000-4000-8000-000000000001",
"professional_id": "18342d1b-0000-4000-8000-000000000001",
"duration_minutes": 30,
"precio_clp": 28000,
"active": true,
"created_at": "2026-09-22T22:21:14.591Z",
"updated_at": "2026-09-22T22:21:14.591Z",
"professional_nombre": "Ana"
}
]
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /clinic/services/{id}/professionals
Set who may perform a prestación
Replaces the WHOLE set in one transaction. An empty array clears it, which means "anyone may". 409 duplicate_professional when the body names the same professional twice.
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 |
|---|---|---|---|
professionals | object[] | yes |
curl -X PUT https://api.vitrinadev.com/api/v1/clinic/services/<id>/professionals \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"professionals": [
{
"professional_id": "18342d1b-0000-4000-8000-000000000001",
"duration_minutes": 30,
"precio_clp": 28000
}
]
}'Example response (200)
{
"data": [
{
"id": "18342d1b-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"clinic_service_id": "4cf5bc59-0000-4000-8000-000000000001",
"professional_id": "18342d1b-0000-4000-8000-000000000001",
"duration_minutes": 30,
"precio_clp": 28000,
"active": true,
"created_at": "2026-09-22T22:21:14.591Z",
"updated_at": "2026-09-22T22:21:14.591Z",
"professional_nombre": "Ana"
}
]
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
Clinical record
What was done to a person and why: encounters, signed notes, antecedentes, alerts, intake forms and the chart with its history. Marked sensitive.
Templates and retention
The texts and the questions before anybody signs or answers them, and how many years each kind of document is kept. They name no patient, and are therefore not sensitive.