Plantillas y conservación
Los textos y las preguntas antes de que nadie los firme o los responda, y cuántos años se guarda cada tipo de documento. No nombran a ningún paciente, y por eso no son sensibles.
Descarga la proyección completa de la API pública: openapi.json.
Firmar y revocar un consentimiento explica este recurso en prosa, con ejemplos ejecutables.
| Método | Ruta | Qué hace |
|---|---|---|
GET | /clinic/consent-templates | Consent templates |
POST | /clinic/consent-templates | Create a consent template (with its first draft version) |
GET | /clinic/consent-templates/{id} | One consent template with its versions, live and draft |
PATCH | /clinic/consent-templates/{id} | Rename, re-scope or change the allowed signature methods |
POST | /clinic/consent-templates/{id}/draft | Save the draft text and its clauses |
POST | /clinic/consent-templates/{id}/publish | Publish the draft version |
POST | /clinic/consent-templates/{id}/retire | Retire a consent template |
POST | /clinic/consent-templates/{id}/versions | Start version n+1 from the live one |
GET | /clinic/form-templates | Form templates (the configurable ficha) |
POST | /clinic/form-templates | Create a form template (with its first draft version) |
GET | /clinic/form-templates/{id} | One template with every version, the live one and the draft |
PATCH | /clinic/form-templates/{id} | Rename or re-scope a template |
POST | /clinic/form-templates/{id}/draft | Save the questions of the draft version |
POST | /clinic/form-templates/{id}/publish | Publish the draft version |
POST | /clinic/form-templates/{id}/retire | Retire a template |
POST | /clinic/form-templates/{id}/versions | Start version n+1 from the live one |
GET | /clinic/retention | Retention policy per document kind |
PUT | /clinic/retention | Set how many years one kind of document is kept |
GET /clinic/consent-templates
Consent templates
Requires clinic:read. Templates name no patient, so they write no PHI access event.
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 |
|---|---|---|---|---|
status | query | draft \ | published \ | retired |
curl https://api.vitrinadev.com/api/v1/clinic/consent-templates \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"data": [
{
"id": "3226ecbe-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Consentimiento de ortodoncia",
"description": "Tratamiento de ortodoncia fija, riesgos y alternativas",
"specialty_id": null,
"status": "draft",
"signature_methods": [
"tablet",
"public_link"
],
"current_version": null,
"published_at": null,
"retired_at": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.641Z",
"updated_at": "2026-09-22T22:21:17.641Z"
}
],
"total": 1
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/consent-templates
Create a consent template (with its first draft version)
signature_methods is per template: a consent a clinic insists on taking in the box must not be signable from a link. Requires clinic_admin:write.
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 |
|---|---|---|---|
name | string | sí | mín. 1, máx. 160 |
description | string | null | — | máx. 600 |
specialty_id | string | null | — | |
signature_methods | tablet \ | public_link \ | whatsapp_otp \ |
body_html | string | — | máx. 200000 |
allows_photos | boolean | — | |
allows_marketing_use | boolean | — |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/consent-templates \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Consentimiento de ortodoncia",
"description": "Tratamiento de ortodoncia fija, riesgos y alternativas",
"signature_methods": [
"tablet",
"public_link"
],
"body_html": "<p>Declaro haber sido informada del tratamiento propuesto…</p>",
"allows_photos": true
}'Ejemplo de respuesta (201)
{
"data": {
"template": {
"id": "3226ecbe-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Consentimiento de ortodoncia",
"description": "Tratamiento de ortodoncia fija, riesgos y alternativas",
"specialty_id": null,
"status": "draft",
"signature_methods": [
"tablet",
"public_link"
],
"current_version": null,
"published_at": null,
"retired_at": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.641Z",
"updated_at": "2026-09-22T22:21:17.641Z"
},
"version": {
"id": "c692273d-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000001",
"version": 1,
"body_html": "<p>Declaro haber sido informada del tratamiento propuesto…</p>",
"allows_photos": true,
"allows_marketing_use": false,
"status": "draft",
"change_note": null,
"published_at": null,
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.641Z",
"updated_at": "2026-09-22T22:21:17.641Z"
}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/consent-templates/{id}
One consent template with its versions, live and draft
live is what a new consent would pin; allows_photos / allows_marketing_use say what the TEXT covers (the patient’s own answers live on the signed consent). Requires clinic: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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/clinic/consent-templates/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"template": {
"id": "3226ecbe-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Consentimiento de ortodoncia",
"description": "Tratamiento de ortodoncia fija, riesgos y alternativas",
"specialty_id": null,
"status": "draft",
"signature_methods": [
"tablet",
"public_link"
],
"current_version": null,
"published_at": null,
"retired_at": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.641Z",
"updated_at": "2026-09-22T22:21:17.641Z"
},
"versions": [
{
"id": "c692273d-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000001",
"version": 1,
"body_html": "<p>Declaro haber sido informada del tratamiento propuesto…</p>",
"allows_photos": true,
"allows_marketing_use": false,
"status": "draft",
"change_note": null,
"published_at": null,
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.641Z",
"updated_at": "2026-09-22T22:21:17.641Z"
}
],
"live": null,
"draft": {
"id": "c692273d-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000001",
"version": 1,
"body_html": "<p>Declaro haber sido informada del tratamiento propuesto…</p>",
"allows_photos": true,
"allows_marketing_use": false,
"status": "draft",
"change_note": null,
"published_at": null,
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.641Z",
"updated_at": "2026-09-22T22:21:17.641Z"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /clinic/consent-templates/{id}
Rename, re-scope or change the allowed signature methods
Identity only — never the text. Requires clinic_admin:write.
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 |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
name | string | — | mín. 1, máx. 160 |
description | string | null | — | máx. 600 |
specialty_id | string | null | — | |
signature_methods | tablet \ | public_link \ | whatsapp_otp \ |
curl -X PATCH https://api.vitrinadev.com/api/v1/clinic/consent-templates/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"description": "Ortodoncia fija: riesgos, alternativas y cuidados"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "3226ecbe-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Consentimiento de ortodoncia",
"description": "Ortodoncia fija: riesgos, alternativas y cuidados",
"specialty_id": null,
"status": "draft",
"signature_methods": [
"tablet",
"public_link"
],
"current_version": null,
"published_at": null,
"retired_at": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.641Z",
"updated_at": "2026-09-22T22:21:17.660Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/consent-templates/{id}/draft
Save the draft text and its clauses
A PUBLISHED consent text can never be edited — it is the evidence of what a patient agreed to, and editing it retroactively changes what they agreed to. allows_marketing_use cannot be set without allows_photos. Requires clinic_admin:write.
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 |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
body_html | string | — | máx. 200000 |
allows_photos | boolean | — | |
allows_marketing_use | boolean | — | |
change_note | string | null | — | máx. 400 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/consent-templates/<id>/draft \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"body_html": "<p>Declaro haber sido informada del tratamiento, sus riesgos y sus alternativas.</p>",
"allows_photos": true,
"change_note": "Se agregan las alternativas"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "c692273d-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000001",
"version": 1,
"body_html": "<p>Declaro haber sido informada del tratamiento, sus riesgos y sus alternativas.</p>",
"allows_photos": true,
"allows_marketing_use": false,
"status": "draft",
"change_note": "Se agregan las alternativas",
"published_at": null,
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.641Z",
"updated_at": "2026-09-22T22:21:17.668Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/consent-templates/{id}/publish
Publish the draft version
Refused when the text is empty: the text is what the patient agrees to. Requires clinic_admin:write.
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 |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/consent-templates/<id>/publish \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"template": {
"id": "3226ecbe-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Consentimiento de ortodoncia",
"description": "Ortodoncia fija: riesgos, alternativas y cuidados",
"specialty_id": null,
"status": "published",
"signature_methods": [
"tablet",
"public_link"
],
"current_version": 1,
"published_at": "2026-09-22T22:21:17.677Z",
"retired_at": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.641Z",
"updated_at": "2026-09-22T22:21:17.675Z"
},
"version": {
"id": "c692273d-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000001",
"version": 1,
"body_html": "<p>Declaro haber sido informada del tratamiento, sus riesgos y sus alternativas.</p>",
"allows_photos": true,
"allows_marketing_use": false,
"status": "published",
"change_note": "Se agregan las alternativas",
"published_at": "2026-09-22T22:21:17.677Z",
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.641Z",
"updated_at": "2026-09-22T22:21:17.675Z"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/consent-templates/{id}/retire
Retire a consent template
No new consents; every signed one keeps rendering its pinned text. Requires clinic_admin:write.
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 |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/consent-templates/<id>/retire \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "f5a82842-0000-4000-8000-000000000001",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Consentimiento en desuso",
"description": null,
"specialty_id": null,
"status": "retired",
"signature_methods": [
"tablet",
"public_link"
],
"current_version": null,
"published_at": null,
"retired_at": "2026-09-22T22:21:17.772Z",
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.764Z",
"updated_at": "2026-09-22T22:21:17.771Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/consent-templates/{id}/versions
Start version n+1 from the live one
Requires clinic_admin:write.
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 |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/consent-templates/<id>/versions \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (201)
{
"data": {
"id": "c692273d-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000001",
"version": 2,
"body_html": "<p>Declaro haber sido informada del tratamiento, sus riesgos y sus alternativas.</p>",
"allows_photos": true,
"allows_marketing_use": false,
"status": "draft",
"change_note": null,
"published_at": null,
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.687Z",
"updated_at": "2026-09-22T22:21:17.687Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/form-templates
Form templates (the configurable ficha)
The «tipo de ficha» catalogue. Requires clinic:read — a receptionist picking a ficha must be able to list them. Templates name no patient, so they write no PHI access event.
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 |
|---|---|---|---|---|
status | query | draft \ | published \ | retired |
kind | query | intake \ | encounter \ | followup |
specialty_id | query | uuid | no | |
patient_fillable | query | true \ | false | no |
curl https://api.vitrinadev.com/api/v1/clinic/form-templates \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"data": [
{
"id": "3226ecbe-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Ficha de ingreso",
"description": null,
"specialty_id": null,
"kind": "intake",
"status": "draft",
"patient_fillable": true,
"current_version": null,
"published_at": null,
"retired_at": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.699Z",
"updated_at": "2026-09-22T22:21:17.699Z"
}
],
"total": 1
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/form-templates
Create a form template (with its first draft version)
A template is never born without a version — the row and its v1 draft are written in one transaction. Requires clinic_admin:write.
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 |
|---|---|---|---|
name | string | sí | mín. 1, máx. 160 |
description | string | null | — | máx. 600 |
specialty_id | string | null | — | |
kind | intake \ | encounter \ | followup |
patient_fillable | boolean | — | |
schema | object | — |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/form-templates \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Ficha de ingreso",
"kind": "intake",
"patient_fillable": true,
"schema": {
"sections": [
{
"key": "salud",
"title": "Antecedentes de salud",
"fields": [
{
"key": "alergias",
"type": "text",
"label": "¿Tiene alergias?",
"required": true
},
{
"key": "embarazo",
"type": "select",
"label": "¿Está embarazada?",
"options": [
{
"value": "si",
"label": "Sí"
},
{
"value": "no",
"label": "No"
}
]
}
]
}
]
}
}'Ejemplo de respuesta (201)
{
"data": {
"template": {
"id": "3226ecbe-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Ficha de ingreso",
"description": null,
"specialty_id": null,
"kind": "intake",
"status": "draft",
"patient_fillable": true,
"current_version": null,
"published_at": null,
"retired_at": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.699Z",
"updated_at": "2026-09-22T22:21:17.699Z"
},
"version": {
"id": "c692273d-0000-4000-8000-000000000003",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000002",
"version": 1,
"schema": {
"sections": [
{
"key": "salud",
"title": "Antecedentes de salud",
"fields": [
{
"key": "alergias",
"type": "text",
"label": "¿Tiene alergias?",
"required": true
},
{
"key": "embarazo",
"type": "select",
"label": "¿Está embarazada?",
"options": [
{
"label": "Sí",
"value": "si"
},
{
"label": "No",
"value": "no"
}
]
}
]
}
]
},
"status": "draft",
"change_note": null,
"published_at": null,
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.699Z",
"updated_at": "2026-09-22T22:21:17.699Z"
}
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/form-templates/{id}
One template with every version, the live one and the draft
The editor reads this: live is what a new response would pin, draft is what «publicar cambios» would promote. Requires clinic: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.
| Parámetro | En | Tipo | Obligatorio | Restricciones |
|---|---|---|---|---|
id | path | uuid | sí |
curl https://api.vitrinadev.com/api/v1/clinic/form-templates/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"template": {
"id": "3226ecbe-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Ficha de ingreso",
"description": null,
"specialty_id": null,
"kind": "intake",
"status": "draft",
"patient_fillable": true,
"current_version": null,
"published_at": null,
"retired_at": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.699Z",
"updated_at": "2026-09-22T22:21:17.699Z"
},
"versions": [
{
"id": "c692273d-0000-4000-8000-000000000003",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000002",
"version": 1,
"schema": {
"sections": [
{
"key": "salud",
"title": "Antecedentes de salud",
"fields": [
{
"key": "alergias",
"type": "text",
"label": "¿Tiene alergias?",
"required": true
},
{
"key": "embarazo",
"type": "select",
"label": "¿Está embarazada?",
"options": [
{
"label": "Sí",
"value": "si"
},
{
"label": "No",
"value": "no"
}
]
}
]
}
]
},
"status": "draft",
"change_note": null,
"published_at": null,
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.699Z",
"updated_at": "2026-09-22T22:21:17.699Z"
}
],
"live": null,
"draft": {
"id": "c692273d-0000-4000-8000-000000000003",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000002",
"version": 1,
"schema": {
"sections": [
{
"key": "salud",
"title": "Antecedentes de salud",
"fields": [
{
"key": "alergias",
"type": "text",
"label": "¿Tiene alergias?",
"required": true
},
{
"key": "embarazo",
"type": "select",
"label": "¿Está embarazada?",
"options": [
{
"label": "Sí",
"value": "si"
},
{
"label": "No",
"value": "no"
}
]
}
]
}
]
},
"status": "draft",
"change_note": null,
"published_at": null,
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.699Z",
"updated_at": "2026-09-22T22:21:17.699Z"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /clinic/form-templates/{id}
Rename or re-scope a template
IDENTITY ONLY — never the questions. Renaming a ficha must not fork it, which is exactly why the questions live on a version and not here. Requires clinic_admin:write.
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 |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
name | string | — | mín. 1, máx. 160 |
description | string | null | — | máx. 600 |
specialty_id | string | null | — | |
kind | intake \ | encounter \ | followup |
patient_fillable | boolean | — |
curl -X PATCH https://api.vitrinadev.com/api/v1/clinic/form-templates/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"description": "La completa el paciente antes de la primera atención"
}'Ejemplo de respuesta (200)
{
"data": {
"id": "3226ecbe-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Ficha de ingreso",
"description": "La completa el paciente antes de la primera atención",
"specialty_id": null,
"kind": "intake",
"status": "draft",
"patient_fillable": true,
"current_version": null,
"published_at": null,
"retired_at": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.699Z",
"updated_at": "2026-09-22T22:21:17.730Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/form-templates/{id}/draft
Save the questions of the draft version
Creates the draft if there is none. A PUBLISHED version can never be edited — the database refuses it — because it is what existing responses render against. Requires clinic_admin:write.
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 |
|---|---|---|---|---|
id | path | uuid | sí |
Cuerpo
| Campo | Tipo | Obligatorio | Restricciones |
|---|---|---|---|
schema | object | sí | |
change_note | string | null | — | máx. 400 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/form-templates/<id>/draft \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"change_note": "Se agrega la pregunta por medicamentos",
"schema": {
"sections": [
{
"key": "salud",
"title": "Antecedentes de salud",
"fields": [
{
"key": "alergias",
"type": "text",
"label": "¿Tiene alergias?",
"required": true
},
{
"key": "medicamentos",
"type": "text",
"label": "¿Toma algún medicamento?"
}
]
}
]
}
}'Ejemplo de respuesta (200)
{
"data": {
"id": "c692273d-0000-4000-8000-000000000003",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000002",
"version": 1,
"schema": {
"sections": [
{
"key": "salud",
"title": "Antecedentes de salud",
"fields": [
{
"key": "alergias",
"type": "text",
"label": "¿Tiene alergias?",
"required": true
},
{
"key": "medicamentos",
"type": "text",
"label": "¿Toma algún medicamento?"
}
]
}
]
},
"status": "draft",
"change_note": "Se agrega la pregunta por medicamentos",
"published_at": null,
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.699Z",
"updated_at": "2026-09-22T22:21:17.739Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/form-templates/{id}/publish
Publish the draft version
The draft becomes live, the previous live version is retired, and the template points at the new number — one transaction. Existing responses keep rendering the version they pinned. Requires clinic_admin:write.
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 |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/form-templates/<id>/publish \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"template": {
"id": "3226ecbe-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Ficha de ingreso",
"description": "La completa el paciente antes de la primera atención",
"specialty_id": null,
"kind": "intake",
"status": "published",
"patient_fillable": true,
"current_version": 1,
"published_at": "2026-09-22T22:21:17.748Z",
"retired_at": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.699Z",
"updated_at": "2026-09-22T22:21:17.746Z"
},
"version": {
"id": "c692273d-0000-4000-8000-000000000003",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000002",
"version": 1,
"schema": {
"sections": [
{
"key": "salud",
"title": "Antecedentes de salud",
"fields": [
{
"key": "alergias",
"type": "text",
"label": "¿Tiene alergias?",
"required": true
},
{
"key": "medicamentos",
"type": "text",
"label": "¿Toma algún medicamento?"
}
]
}
]
},
"status": "published",
"change_note": "Se agrega la pregunta por medicamentos",
"published_at": "2026-09-22T22:21:17.748Z",
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.699Z",
"updated_at": "2026-09-22T22:21:17.746Z"
}
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/form-templates/{id}/retire
Retire a template
No new responses; every existing one still renders forever. Requires clinic_admin:write.
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 |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/form-templates/<id>/retire \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"id": "f5a82842-0000-4000-8000-000000000002",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"name": "Ficha en desuso",
"description": null,
"specialty_id": null,
"kind": "intake",
"status": "retired",
"patient_fillable": false,
"current_version": null,
"published_at": null,
"retired_at": "2026-09-22T22:21:17.785Z",
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.776Z",
"updated_at": "2026-09-22T22:21:17.784Z"
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/form-templates/{id}/versions
Start version n+1 from the live one
Seeded from the published version, because a new version of a ficha is almost always the old one plus a question. Idempotent: a template that already has a draft returns it. Requires clinic_admin:write.
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 |
|---|---|---|---|---|
id | path | uuid | sí |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/form-templates/<id>/versions \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (201)
{
"data": {
"id": "c692273d-0000-4000-8000-000000000004",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"template_id": "3226ecbe-0000-4000-8000-000000000002",
"version": 2,
"schema": {
"sections": [
{
"key": "salud",
"title": "Antecedentes de salud",
"fields": [
{
"key": "alergias",
"type": "text",
"label": "¿Tiene alergias?",
"required": true
},
{
"key": "medicamentos",
"type": "text",
"label": "¿Toma algún medicamento?"
}
]
}
]
},
"status": "draft",
"change_note": null,
"published_at": null,
"published_by_user_id": null,
"created_by_user_id": null,
"created_at": "2026-09-22T22:21:17.756Z",
"updated_at": "2026-09-22T22:21:17.756Z"
}
}Responde: 201 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/retention
Retention policy per document kind
EVERY kind is returned, always — a settings screen with holes in it is a screen a clinic cannot reason about. Kinds the tenant never configured render their legal floor and say so (is_default). Requires clinic: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/retention \
-H "Authorization: Bearer $VITRINA_KEY"Ejemplo de respuesta (200)
{
"data": {
"data": [
{
"kind": "examen",
"retention_years": 15,
"legal_minimum_years": 15,
"is_default": true
},
{
"kind": "imagen",
"retention_years": 15,
"legal_minimum_years": 15,
"is_default": true
},
{
"kind": "informe",
"retention_years": 15,
"legal_minimum_years": 15,
"is_default": true
}
],
"total": 10
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /clinic/retention
Set how many years one kind of document is kept
REFUSED below the legal minimum, with the legal reason — 15 years for clinical documents (Ley 20.584 / Decreto 41), 6 for tax documents (SII). The floor is also a CHECK constraint, so it is a property of the database rather than of a form validator. Requires clinic_admin:write.
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 |
|---|---|---|---|
kind | examen \ | imagen \ | informe \ |
retention_years | integer | sí | ≥ 1, ≤ 100 |
curl -X PUT https://api.vitrinadev.com/api/v1/clinic/retention \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"kind": "consentimiento",
"retention_years": 15
}'Ejemplo de respuesta (200)
{
"data": {
"kind": "consentimiento",
"retention_years": 15,
"legal_minimum_years": 15,
"is_default": false
}
}Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429
Prestaciones de la clínica
Qué hace la clínica: duración, precio de lista, requisitos de consentimiento y quién puede ejecutar cada prestación.
Feed bancario de la clínica
Los movimientos bancarios de la clínica, desde correo, Fintoc o la API del banco, normalizados a un mismo formato para conciliar la caja.