Recursos humanos de la clínica
La conexión de solo lectura con Buk y el costo de nómina del mes, sumado a partir de las liquidaciones cerradas sin guardar el detalle por persona.
Descarga la proyección completa de la API pública: openapi.json.
| Método | Ruta | Qué hace |
|---|---|---|
PUT | /clinic/hr/buk/concept | Choose the Buk concept for commissions |
POST | /clinic/hr/buk/connect | Connect (or rotate) the tenant’s Buk API token |
POST | /clinic/hr/buk/disconnect | Disconnect and wipe the stored Buk token |
GET | /clinic/hr/buk/items | List the Buk concepts the clinic can pick |
GET | /clinic/hr/buk/mapping | Buk mapping: professionals ↔ Buk employees and the commission concept |
DELETE | /clinic/hr/buk/mapping/{professionalId} | Remove a professional’s Buk match |
POST | /clinic/hr/buk/mapping/confirm | Confirm suggested Buk matches |
POST | /clinic/hr/buk/mapping/match | Find the professionals in Buk by RUT |
POST | /clinic/hr/buk/push | Enviar a Buk — push a closed commission period as variable pay |
GET | /clinic/hr/buk/pushes | Buk push log |
GET | /clinic/hr/buk/status | Buk payroll connection status |
POST | /clinic/hr/buk/sync | Sincronizar ahora — pull last month’s payroll cost from Buk |
PUT /clinic/hr/buk/concept
Choose the Buk concept for commissions
Maps the commission liquidación to one Buk item. Refused (422) unless the id is in GET /clinic/hr/buk/items.
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.
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
buk_item_id | integer | sí | > 0 |
curl -X PUT https://api.vitrinadev.com/api/v1/clinic/hr/buk/concept \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"buk_item_id": 4021
}'Ejemplo de respuesta (200)
{
"data": {
"buk_item_id": 4021,
"buk_item_name": "Bono por comisiones"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/hr/buk/connect
Connect (or rotate) the tenant’s Buk API token
One Buk (buk.cl) connection per tenant: the company subdomain plus a read-only auth_token API key a human mints inside Buk (Configuración → Accesos API). Every sync reads ONLY the payroll_detail/month operation (Buk has no company-wide aggregate endpoint) and sums the CLOSED settlements in memory — the raw per-employee response (which carries rut) never leaves the provider client. Upserts BY TENANT — a second call with a new token rotates the stored credential rather than creating a second connection. The token is AES-GCM enveloped under the tenant’s own DEK before it is written; only a masked preview is ever returned.
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.
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
subdomain | string | sí | mín. 2, máx. 63, patrón ^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$ |
auth_token | string | sí | mín. 8, máx. 500 |
country | chile | — |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/hr/buk/connect \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"subdomain": "clinicaodm",
"auth_token": "a1b2c3d4e5f6a7b8c9d0e1f2a3b4c5d6",
"country": "chile"
}'Ejemplo de respuesta (200)
{
"data": {
"connected": true,
"id": "b6b6b6b6-0000-4000-8000-000000000001",
"subdomain": "clinicaodm",
"country": "chile",
"has_credentials": true,
"auth_token_preview": "a1b2••••d6",
"enabled": true,
"last_sync_at": "2026-09-22T09:05:11.000Z",
"last_sync_status": "ok",
"last_sync_error": null,
"created_at": "2026-08-01T13:00:00.000Z",
"updated_at": "2026-09-22T09:05:11.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/hr/buk/disconnect
Disconnect and wipe the stored Buk token
Disables the connection and erases the stored token — never leaves an encrypted secret behind with no way to use it. Reconnecting is POST .../connect again with a fresh token.
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 -X POST https://api.vitrinadev.com/api/v1/clinic/hr/buk/disconnect \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"connected": false,
"disconnected": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/hr/buk/items
List the Buk concepts the clinic can pick
Buk's variable-items API, narrowed to assignable haberes with a per-person variable amount.
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/hr/buk/items \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"items": [
{
"id": 4021,
"name": "Bono por comisiones",
"code": "BONO_COM"
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/hr/buk/mapping
Buk mapping: professionals ↔ Buk employees and the commission concept
Buk stays the payroll system of record; Vitrina computes and exports, and never pays. The key Buk issued needs ítems «Lectura y Modificación», empleados «Lectura» and, to attach the liquidación PDF, «subir documentos». Each professional carries its match state and the plain next step; ready_to_push says whether an export can run.
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/hr/buk/mapping \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"connected": true,
"concept": {
"buk_item_id": 4021,
"buk_item_name": "Bono por comisiones"
},
"professionals": [
{
"professional_id": "b6b6b6b6-0000-4000-8000-000000000011",
"name": "Camila Rojas Soto",
"rut": "12.345.678-5",
"state": "confirmed",
"buk_employee_name": "Camila Rojas Soto",
"confirmed_at": "2026-10-01T14:02:00.000Z",
"next_action": "Listo para enviar."
}
],
"counts": {
"confirmed": 1,
"suggested": 0,
"needs_attention": 0
},
"ready_to_push": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /clinic/hr/buk/mapping/{professionalId}
Remove a professional’s Buk match
The professional is blocked from pushes until matched again. Items already in Buk are untouched.
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 -X DELETE https://api.vitrinadev.com/api/v1/clinic/hr/buk/mapping/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"removed": true
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/hr/buk/mapping/confirm
Confirm suggested Buk matches
The owner confirms once; only confirmed matches are pushed to. Omit professional_ids to confirm every suggestion.
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.
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
professional_ids | uuid[] | — |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/hr/buk/mapping/confirm \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"professional_ids": [
"b6b6b6b6-0000-4000-8000-000000000011"
]
}'Ejemplo de respuesta (200)
{
"data": {
"confirmed": 1
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/hr/buk/mapping/match
Find the professionals in Buk by RUT
Reads Buk’s employee list in memory (RUTs are never stored) and records each RUT hit as a SUGGESTION. A confirmed match is never touched. Professionals without a match come back with a reason.
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 -X POST https://api.vitrinadev.com/api/v1/clinic/hr/buk/mapping/match \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"matched": 4,
"unmatched": [
{
"professional_id": "b6b6b6b6-0000-4000-8000-000000000012",
"name": "Daniel Pino Vega",
"reason_code": "not_in_buk",
"reason": "No hay un colaborador con este RUT en Buk."
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/hr/buk/push
Enviar a Buk — push a closed commission period as variable pay
Buk stays the payroll system of record; Vitrina computes and exports, and never pays. The key Buk issued needs ítems «Lectura y Modificación», empleados «Lectura» and, to attach the liquidación PDF, «subir documentos». One Buk assignment per professional and month (created through Buk's assignments API with overwrite_existing_assign), so a re-send UPDATES instead of duplicating. Each professional ends sent, blocked (not sent; reason says what to fix: no confirmed match, unapproved lines, $0) or failed (Buk refused or was unreachable; retry with professional_ids/only_unsent). A blocked professional never blocks another. The liquidación PDF is attached to the Buk employee file when Buk allows it (document_status); a refusal there does not un-send the item. Sent lines are marked exported.
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.
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
period | string | sí | patrón ^\d{4}-(0[1-9]|1[0-2])$ |
professional_ids | uuid[] | — | |
only_unsent | boolean | — |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/hr/buk/push \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"period": "2026-09"
}'Ejemplo de respuesta (200)
{
"data": {
"period": "2026-09",
"results": [
{
"id": "b6b6b6b6-0000-4000-8000-000000000021",
"idempotency_key": "b6b6b6b6-0000-4000-8000-000000000011:2026-09:commission",
"professional_id": "b6b6b6b6-0000-4000-8000-000000000011",
"professional_name": "Camila Rojas Soto",
"period": "2026-09",
"concept": "commission",
"amount_clp": 1250000,
"status": "sent",
"reason_code": null,
"reason": null,
"buk_employee_id": 731,
"buk_item_id": 4021,
"buk_assign_id": 90321,
"document_status": "attached",
"document_error": null,
"pushed_by": "00000000-0000-4000-8000-0000000000aa",
"pushed_at": "2026-10-02T15:30:00.000Z"
},
{
"id": "b6b6b6b6-0000-4000-8000-000000000022",
"idempotency_key": "b6b6b6b6-0000-4000-8000-000000000012:2026-09:commission",
"professional_id": "b6b6b6b6-0000-4000-8000-000000000012",
"professional_name": "Daniel Pino Vega",
"period": "2026-09",
"concept": "commission",
"amount_clp": 480000,
"status": "blocked",
"reason_code": "employee_not_matched",
"reason": "No está vinculado a un colaborador de Buk. Vincúlalo en «Vinculación con Buk».",
"buk_employee_id": null,
"buk_item_id": null,
"buk_assign_id": null,
"document_status": null,
"document_error": null,
"pushed_by": "00000000-0000-4000-8000-0000000000aa",
"pushed_at": "2026-10-02T15:30:00.000Z"
}
],
"summary": {
"sent": 1,
"blocked": 1,
"failed": 0,
"skipped_already_sent": 0,
"total_sent_clp": 1250000
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/hr/buk/pushes
Buk push log
Who, when, amount and Buk’s outcome per professional, newest first. latest_only=true collapses to the current state of each professional-month.
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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
period | query | string | no | patrón ^\d{4}-(0[1-9]|1[0-2])$ |
latest_only | query | true \ | false | no |
limit | query | integer | no | ≥ 1, ≤ 500 |
curl https://api.vitrinadev.com/api/v1/clinic/hr/buk/pushes \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"items": [
{
"id": "b6b6b6b6-0000-4000-8000-000000000021",
"idempotency_key": "b6b6b6b6-0000-4000-8000-000000000011:2026-09:commission",
"professional_id": "b6b6b6b6-0000-4000-8000-000000000011",
"professional_name": "Camila Rojas Soto",
"period": "2026-09",
"concept": "commission",
"amount_clp": 1250000,
"status": "sent",
"reason_code": null,
"reason": null,
"buk_employee_id": 731,
"buk_item_id": 4021,
"buk_assign_id": 90321,
"document_status": "attached",
"document_error": null,
"pushed_by": "00000000-0000-4000-8000-0000000000aa",
"pushed_at": "2026-10-02T15:30:00.000Z"
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/hr/buk/status
Buk payroll connection status
One Buk (buk.cl) connection per tenant: the company subdomain plus a read-only auth_token API key a human mints inside Buk (Configuración → Accesos API). Every sync reads ONLY the payroll_detail/month operation (Buk has no company-wide aggregate endpoint) and sums the CLOSED settlements in memory — the raw per-employee response (which carries rut) never leaves the provider client. Readable with clinic_money:read.
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/hr/buk/status \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"connected": true,
"id": "b6b6b6b6-0000-4000-8000-000000000001",
"subdomain": "clinicaodm",
"country": "chile",
"has_credentials": true,
"auth_token_preview": "a1b2••••d6",
"enabled": true,
"last_sync_at": "2026-09-22T09:05:11.000Z",
"last_sync_status": "ok",
"last_sync_error": null,
"created_at": "2026-08-01T13:00:00.000Z",
"updated_at": "2026-09-22T09:05:11.000Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/hr/buk/sync
Sincronizar ahora — pull last month’s payroll cost from Buk
Runs the same aggregate pull the daily tick runs, synchronously, for the caller’s tenant. Targets the LAST FULLY-CLOSED calendar month — a liquidación Buk has not closed yet is skipped, not zeroed, and picked up by a later sync. reason explains a 200 that wrote nothing (no_enabled_connection / no_closed_settlements).
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 -X POST https://api.vitrinadev.com/api/v1/clinic/hr/buk/sync \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"period": "2026-08",
"wrote": true,
"inserted": false,
"amount_clp": 5430000,
"settlement_count": 6,
"skipped_open_count": 0,
"skipped_unparsable_count": 0
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
Esterilización de la clínica
El registro de ciclos de esterilización: equipo, lote, fecha y hora, quién lo realizó, resultado con su indicador y los paquetes del ciclo, con exportación CSV y PDF por período y equipo; el lote usado queda anotado en la atención.
Laboratorio de la clínica
Los laboratorios de la clínica, su lista de precios por tipo de trabajo y los pedidos que se les envían, con el estado de cada pedido.