Caja de la clínica
El turno en una sucursal: abrirlo con su fondo, cerrarlo contra un conteo y firmar el arqueo.
Descarga la proyección completa de la API pública: openapi.json.
Presupuestar un plan y cerrar caja explica este recurso en prosa, con ejemplos ejecutables.
| Método | Ruta | Qué hace |
|---|---|---|
GET | /clinic/cash-sessions | List caja sessions |
POST | /clinic/cash-sessions | Open the drawer |
GET | /clinic/cash-sessions/{id} | One caja session and its payments |
POST | /clinic/cash-sessions/{id}/close | Close the drawer against a count |
POST | /clinic/cash-sessions/{id}/reconcile | Sign off a counted shift |
GET | /clinic/cash-sessions/current | The open caja session at a sucursal |
GET | /clinic/cash-sessions/open | List every open caja session |
GET /clinic/cash-sessions
List caja sessions
The shift history, newest first, each with its expected vs counted and the stored difference (SIGNED: negative is short, positive is over) plus the reason somebody wrote for it. from/to are inclusive calendar days over the day the drawer was OPENED, so a late close that crossed midnight stays with the shift it belongs to.
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 |
|---|---|---|---|---|
location_id | query | uuid | no | |
status | query | open \ | closed \ | reconciled |
from | query | string | no | patrón `^\d4-(0[1-9]\ |
to | query | string | no | patrón `^\d4-(0[1-9]\ |
limit | query | integer | no | ≥ 1, ≤ 200, por defecto 50 |
offset | query | integer | null | no | ≥ 0, por defecto 0 |
curl https://api.vitrinadev.com/api/v1/clinic/cash-sessions \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"items": [
{
"id": "d1d832c4-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"location_id": "b1b1b1b1-0000-4000-8000-000000000002",
"opened_by_user_id": "11111111-0000-4000-8000-000000000001",
"opened_at": "2026-09-22T22:21:16.863Z",
"opening_float_clp": 30000,
"closed_by_user_id": null,
"closed_at": null,
"expected_clp": null,
"counted_clp": null,
"difference_clp": null,
"difference_reason": null,
"status": "open",
"note": "Turno mañana",
"created_at": "2026-09-22T22:21:16.863Z",
"updated_at": "2026-09-22T22:21:16.863Z",
"location_name": "Sucursal Maipú",
"running_expected_clp": 30000,
"collected_clp": 0,
"payments": 0,
"by_instrument": []
}
],
"count": 1,
"difference_clp": 0
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/cash-sessions
Open the drawer
One open session per sucursal, enforced by a partial unique index — a second attempt answers 409 rather than creating a parallel shift. Requires a signed-in user: opened_by_user_id is NOT NULL because «quién abrió la caja» is the point of a shift, so an api_key principal is refused rather than stored as a null nobody can chase.
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 |
|---|---|---|---|
location_id | uuid | sí | |
opening_float_clp | integer | — | ≥ 0, ≤ 999999999999 |
note | string | null | — | máx. 500 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/cash-sessions \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"location_id": "b1b1b1b1-0000-4000-8000-000000000002",
"opening_float_clp": 30000,
"note": "Turno mañana"
}'Ejemplo de respuesta (201)
{
"data": {
"id": "d1d832c4-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"location_id": "b1b1b1b1-0000-4000-8000-000000000002",
"opened_by_user_id": "11111111-0000-4000-8000-000000000001",
"opened_at": "2026-09-22T22:21:16.863Z",
"opening_float_clp": 30000,
"closed_by_user_id": null,
"closed_at": null,
"expected_clp": null,
"counted_clp": null,
"difference_clp": null,
"difference_reason": null,
"status": "open",
"note": "Turno mañana",
"created_at": "2026-09-22T22:21:16.863Z",
"updated_at": "2026-09-22T22:21:16.863Z",
"location_name": "Sucursal Maipú",
"running_expected_clp": 30000,
"collected_clp": 0,
"payments": 0,
"by_instrument": []
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/cash-sessions/{id}
One caja session and its payments
The shift plus every payment stamped with it, grouped by instrument in by_instrument and listed in items. A payment is stamped at RECORD TIME while the session is open (payments design §10.1) and never back-filled — back-filling would move money between two already-counted shifts.
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/cash-sessions/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "d1d832c4-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"location_id": "b1b1b1b1-0000-4000-8000-000000000002",
"opened_by_user_id": "11111111-0000-4000-8000-000000000001",
"opened_at": "2026-09-22T22:21:16.863Z",
"opening_float_clp": 30000,
"closed_by_user_id": "11111111-0000-4000-8000-000000000001",
"closed_at": "2026-09-22T22:21:17.127Z",
"expected_clp": 30000,
"counted_clp": 50000,
"difference_clp": 20000,
"difference_reason": "Vuelto de un pago en efectivo",
"status": "closed",
"note": "Turno mañana",
"created_at": "2026-09-22T22:21:16.863Z",
"updated_at": "2026-09-22T22:21:17.127Z",
"location_name": "Sucursal Maipú",
"running_expected_clp": 30000,
"collected_clp": 0,
"payments": 0,
"by_instrument": [],
"items": []
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/cash-sessions/{id}/close
Close the drawer against a count
⚠ THE BODY CARRIES NO expected_clp, AND CANNOT. The server computes the expectation FROM THE LEDGER (opening float + cash stamped with the session, reversed excluded) and returns the difference; a screen that could post its own expectation could hide a shortfall. A non-zero difference REQUIRES a written reason — refused in the service and by a CHECK.
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 |
|---|---|---|---|
counted_clp | integer | sí | ≥ 0, ≤ 999999999999 |
difference_reason | string | null | — | máx. 500 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/cash-sessions/<id>/close \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"counted_clp": 50000,
"difference_reason": "Vuelto de un pago en efectivo"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "d1d832c4-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"location_id": "b1b1b1b1-0000-4000-8000-000000000002",
"opened_by_user_id": "11111111-0000-4000-8000-000000000001",
"opened_at": "2026-09-22T22:21:16.863Z",
"opening_float_clp": 30000,
"closed_by_user_id": "11111111-0000-4000-8000-000000000001",
"closed_at": "2026-09-22T22:21:17.127Z",
"expected_clp": 30000,
"counted_clp": 50000,
"difference_clp": 20000,
"difference_reason": "Vuelto de un pago en efectivo",
"status": "closed",
"note": "Turno mañana",
"created_at": "2026-09-22T22:21:16.863Z",
"updated_at": "2026-09-22T22:21:17.127Z",
"location_name": "Sucursal Maipú",
"running_expected_clp": 30000,
"collected_clp": 0,
"payments": 0,
"by_instrument": [],
"items": []
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/cash-sessions/{id}/reconcile
Sign off a counted shift
The supervisory acceptance of a shift that has already been counted. Only a closed session can be reconciled.
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 |
|---|---|---|---|
note | string | null | — | máx. 500 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/cash-sessions/<id>/reconcile \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"note": "Revisado con el arqueo del turno"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "d1d832c4-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"location_id": "b1b1b1b1-0000-4000-8000-000000000002",
"opened_by_user_id": "11111111-0000-4000-8000-000000000001",
"opened_at": "2026-09-22T22:21:16.863Z",
"opening_float_clp": 30000,
"closed_by_user_id": "11111111-0000-4000-8000-000000000001",
"closed_at": "2026-09-22T22:21:17.127Z",
"expected_clp": 30000,
"counted_clp": 50000,
"difference_clp": 20000,
"difference_reason": "Vuelto de un pago en efectivo",
"status": "reconciled",
"note": "Revisado con el arqueo del turno",
"created_at": "2026-09-22T22:21:16.863Z",
"updated_at": "2026-09-22T22:21:17.146Z",
"location_name": "Sucursal Maipú",
"running_expected_clp": 30000,
"collected_clp": 0,
"payments": 0,
"by_instrument": [],
"items": []
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/cash-sessions/current
The open caja session at a sucursal
The shift at location_id, with running_expected_clp — what the LEDGER says should be in the drawer right now (opening float + cash taken, reversed payments excluded) — and the takings split by instrument. session: null is a 200 and the ordinary morning state, not a 404. Only EFECTIVO counts toward the expectation: a card or a transfer taken at the counter belongs to the shift but never reaches the till.
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 |
|---|---|---|---|---|
location_id | query | uuid | sí |
curl https://api.vitrinadev.com/api/v1/clinic/cash-sessions/current \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"session": {
"id": "d1d832c4-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"location_id": "b1b1b1b1-0000-4000-8000-000000000002",
"opened_by_user_id": "11111111-0000-4000-8000-000000000001",
"opened_at": "2026-09-22T22:21:16.863Z",
"opening_float_clp": 30000,
"closed_by_user_id": null,
"closed_at": null,
"expected_clp": null,
"counted_clp": null,
"difference_clp": null,
"difference_reason": null,
"status": "open",
"note": "Turno mañana",
"created_at": "2026-09-22T22:21:16.863Z",
"updated_at": "2026-09-22T22:21:16.863Z",
"location_name": "Sucursal Maipú",
"running_expected_clp": 30000,
"collected_clp": 0,
"payments": 0,
"by_instrument": []
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/cash-sessions/open
List every open caja session
One per sucursal at most — a partial unique index enforces it. What the sidebar badge reads.
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/cash-sessions/open \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"items": [
{
"id": "d1d832c4-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"location_id": "b1b1b1b1-0000-4000-8000-000000000002",
"opened_by_user_id": "11111111-0000-4000-8000-000000000001",
"opened_at": "2026-09-22T22:21:16.863Z",
"opening_float_clp": 30000,
"closed_by_user_id": null,
"closed_at": null,
"expected_clp": null,
"counted_clp": null,
"difference_clp": null,
"difference_reason": null,
"status": "open",
"note": "Turno mañana",
"created_at": "2026-09-22T22:21:16.863Z",
"updated_at": "2026-09-22T22:21:16.863Z",
"location_name": "Sucursal Maipú"
}
]
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
Presupuestos de la clínica
Presupuestos con folio, sus líneas con el precio congelado y los planes de tratamiento que ordenan lo que se va a hacer.
Consentimientos
El consentimiento informado contra el texto exacto que se firmó, su revocación y la galería clínica que ese consentimiento habilita. Marcado como sensible.