Clinic insurance
The patient's insurance (several, one primary), the coverage table per plan and prestación, and the estimated coverage and copago on the presupuesto and the estado de cuenta, in PDF too. Coverage is never a discount: prices and convenios do not change.
Download the full API pública projection: openapi.json.
| Method | Path | What it does |
|---|---|---|
GET | /clinic/budgets/{id}/coverage | Cobertura and copago of a presupuesto |
GET | /clinic/insurance/plans | List the insurer plans |
POST | /clinic/insurance/plans | Add an insurer plan |
PATCH | /clinic/insurance/plans/{id} | Rename or withdraw an insurer plan |
GET | /clinic/insurance/plans/{id}/coverage | Read a plan’s coverage table |
PUT | /clinic/insurance/plans/{id}/coverage | Set one coverage rule |
DELETE | /clinic/insurance/plans/{id}/coverage/{ruleId} | Remove one coverage rule |
GET | /clinic/patients/{id}/insurance-statement | Estado de cuenta with the seguro’s cobertura |
GET | /clinic/patients/{id}/insurance-statement/render | Estado de cuenta with the seguro, as a PDF |
GET | /clinic/patients/{id}/insurances | List a patient’s seguros |
POST | /clinic/patients/{id}/insurances | Add a seguro to a patient |
DELETE | /clinic/patients/{id}/insurances/{insuranceId} | Remove a patient’s seguro |
PATCH | /clinic/patients/{id}/insurances/{insuranceId} | Edit a patient’s seguro |
GET /clinic/budgets/{id}/coverage
Cobertura and copago of a presupuesto
Per line and in total: price_clp, the seguro’s estimated coverage_clp and the patient’s copay_clp (price = coverage + copay). Uses the patient’s primary seguro, or insurance_id as a what-if. status is covered, no_insurance or insurance_expired; without a usable seguro the copay is the full price. totals.price_clp is the presupuesto’s own total, so a presupuesto-level discount is already in it (budget_discount_clp). id is the budget id or its folio. Derived on read, never frozen; the same figures print on GET /clinic/budgets/\{id\}/render. Requires 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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | any | yes | |
insurance_id | query | uuid | no |
curl https://api.vitrinadev.com/api/v1/clinic/budgets/<id>/coverage \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"budget_id": "e0e57121-0000-4000-8000-0000000009ab",
"status": "covered",
"insurance": {
"id": "c0e57121-0000-4000-8000-0000000007ad",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
"plan_id": "c0e57121-0000-4000-8000-0000000007ab",
"insurer": "Consorcio",
"plan_name": "Salud Plus",
"plan_active": true,
"policy_number": "P-48213",
"holder_name": null,
"valid_until": "2027-03-31",
"is_primary": true,
"created_at": "2026-10-09T17:45:00.000Z",
"updated_at": "2026-10-09T17:45:00.000Z"
},
"lines": [
{
"item_id": "f0e57121-0000-4000-8000-0000000009a1",
"label": "Limpieza dental",
"quantity": 1,
"price_clp": 40000,
"coverage_clp": 28000,
"copay_clp": 12000,
"rule": "service",
"capped": false
},
{
"item_id": "f0e57121-0000-4000-8000-0000000009a2",
"label": "Blanqueamiento",
"quantity": 1,
"price_clp": 120000,
"coverage_clp": 0,
"copay_clp": 120000,
"rule": "none",
"capped": false
}
],
"totals": {
"price_clp": 160000,
"coverage_clp": 28000,
"copay_clp": 132000
},
"budget_discount_clp": 0
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/insurance/plans
List the insurer plans
The seguros the clinic keeps a coverage table for, active first, each with its rule_count. active=true is what the patient form offers. 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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
active | query | true \ | false | no |
curl https://api.vitrinadev.com/api/v1/clinic/insurance/plans \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"items": [
{
"id": "c0e57121-0000-4000-8000-0000000007ab",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"insurer": "Consorcio",
"name": "Salud Plus",
"active": true,
"rule_count": 2,
"created_at": "2026-10-01T13:00:00.000Z",
"updated_at": "2026-10-01T13:00:00.000Z"
}
],
"total": 1
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/insurance/plans
Add an insurer plan
insurer and name are unique together per clinic, ignoring case (409 otherwise). 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.
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
insurer | string | yes | mín. 1, máx. 120 |
name | string | yes | mín. 1, máx. 120 |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/insurance/plans \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"insurer": "Consorcio",
"name": "Salud Plus"
}'Example response (201)
{
"data": {
"id": "c0e57121-0000-4000-8000-0000000007ab",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"insurer": "Consorcio",
"name": "Salud Plus",
"active": true,
"rule_count": 2,
"created_at": "2026-10-01T13:00:00.000Z",
"updated_at": "2026-10-01T13:00:00.000Z"
}
}Answers: 201 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /clinic/insurance/plans/{id}
Rename or withdraw an insurer plan
active: false withdraws it from the patient form; patients who hold it keep it and it keeps covering. Plans are never deleted. 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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
insurer | string | — | mín. 1, máx. 120 |
name | string | — | mín. 1, máx. 120 |
active | boolean | — |
curl -X PATCH https://api.vitrinadev.com/api/v1/clinic/insurance/plans/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"active": false
}'Example response (200)
{
"data": {
"id": "c0e57121-0000-4000-8000-0000000007ab",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"insurer": "Consorcio",
"name": "Salud Plus",
"active": false,
"rule_count": 2,
"created_at": "2026-10-01T13:00:00.000Z",
"updated_at": "2026-10-01T13:00:00.000Z"
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/insurance/plans/{id}/coverage
Read a plan’s coverage table
The default row first, then one row per prestación by name. A percent row carries percent (0 to 100); an amount row carries amount_clp per unit; either may carry a cap_clp per line. 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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
curl https://api.vitrinadev.com/api/v1/clinic/insurance/plans/<id>/coverage \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"items": [
{
"id": "c0e57121-0000-4000-8000-0000000007ac",
"plan_id": "c0e57121-0000-4000-8000-0000000007ab",
"clinic_service_id": "d0e57121-0000-4000-8000-0000000008ab",
"service_name": "Limpieza dental",
"kind": "percent",
"percent": 70,
"amount_clp": null,
"cap_clp": 30000
}
],
"total": 1
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
PUT /clinic/insurance/plans/{id}/coverage
Set one coverage rule
Creates or replaces the plan’s row for clinic_service_id (omit it or send null for the plan default). kind: percent takes percent and no amount; kind: amount takes amount_clp and no percent (400 otherwise). 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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
clinic_service_id | string | null | — | |
kind | percent \ | amount | yes |
percent | number | null | — | ≥ 0, ≤ 100 |
amount_clp | integer | null | — | ≥ 0, ≤ 1000000000 |
cap_clp | integer | null | — | ≥ 0, ≤ 1000000000 |
curl -X PUT https://api.vitrinadev.com/api/v1/clinic/insurance/plans/<id>/coverage \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"clinic_service_id": "d0e57121-0000-4000-8000-0000000008ab",
"kind": "percent",
"percent": 70,
"cap_clp": 30000
}'Example response (200)
{
"data": {
"id": "c0e57121-0000-4000-8000-0000000007ac",
"plan_id": "c0e57121-0000-4000-8000-0000000007ab",
"clinic_service_id": "d0e57121-0000-4000-8000-0000000008ab",
"service_name": "Limpieza dental",
"kind": "percent",
"percent": 70,
"amount_clp": null,
"cap_clp": 30000
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /clinic/insurance/plans/{id}/coverage/{ruleId}
Remove one coverage rule
The prestación falls back to the plan default, or to no cover. 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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes | |
ruleId | path | uuid | yes |
curl -X DELETE https://api.vitrinadev.com/api/v1/clinic/insurance/plans/<id>/coverage/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Answers: 204 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/patients/{id}/insurance-statement
Estado de cuenta with the seguro’s cobertura
The patient’s accepted presupuestos, oldest first, each with price, cobertura and copago per line and in total, and a grand total. A reissued version replaces the one it carries lines from. Payments and the outstanding balance stay the ledger’s answer (GET /contacts/\{id\}/ledger). Requires 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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes | |
insurance_id | query | uuid | no |
curl https://api.vitrinadev.com/api/v1/clinic/patients/<id>/insurance-statement \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"patient_id": "b1b0b8de-0000-4000-8000-000000000001",
"patient_name": "Paciente de ejemplo",
"status": "covered",
"insurance": {
"id": "c0e57121-0000-4000-8000-0000000007ad",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
"plan_id": "c0e57121-0000-4000-8000-0000000007ab",
"insurer": "Consorcio",
"plan_name": "Salud Plus",
"plan_active": true,
"policy_number": "P-48213",
"holder_name": null,
"valid_until": "2027-03-31",
"is_primary": true,
"created_at": "2026-10-09T17:45:00.000Z",
"updated_at": "2026-10-09T17:45:00.000Z"
},
"budgets": [
{
"budget_id": "e0e57121-0000-4000-8000-0000000009ab",
"display_id": "E-12",
"status": "accepted",
"accepted_at": "2026-10-09T18:00:00.000Z",
"lines": [
{
"item_id": "f0e57121-0000-4000-8000-0000000009a1",
"label": "Limpieza dental",
"quantity": 1,
"price_clp": 40000,
"coverage_clp": 28000,
"copay_clp": 12000,
"rule": "service",
"capped": false
},
{
"item_id": "f0e57121-0000-4000-8000-0000000009a2",
"label": "Blanqueamiento",
"quantity": 1,
"price_clp": 120000,
"coverage_clp": 0,
"copay_clp": 120000,
"rule": "none",
"capped": false
}
],
"totals": {
"price_clp": 160000,
"coverage_clp": 28000,
"copay_clp": 132000
},
"budget_discount_clp": 0,
"reimbursement": {
"claimed_clp": 28000,
"reimbursed_clp": 0,
"pending_clp": 28000
}
}
],
"totals": {
"price_clp": 160000,
"coverage_clp": 28000,
"copay_clp": 132000
},
"reimbursement": {
"request_count": 1,
"requested_clp": 28000,
"rejected_clp": 0,
"reimbursed_clp": 0,
"reimbursed_to_clinic_clp": 0,
"reimbursed_to_patient_clp": 0,
"already_counted_clp": 0,
"outside_payments_clp": 0,
"pending_clp": 28000
}
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/patients/{id}/insurance-statement/render
Estado de cuenta with the seguro, as a PDF
The same figures as the JSON statement, on the clinic’s branded paper. Requires 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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes | |
insurance_id | query | uuid | no |
curl https://api.vitrinadev.com/api/v1/clinic/patients/<id>/insurance-statement/render \
-H "Authorization: Bearer $VITRINA_KEY"Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
GET /clinic/patients/{id}/insurances
List a patient’s seguros
Primary first. Besides, never instead of, the previsión on the ficha. 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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
curl https://api.vitrinadev.com/api/v1/clinic/patients/<id>/insurances \
-H "Authorization: Bearer $VITRINA_KEY"Example response (200)
{
"data": {
"items": [
{
"id": "c0e57121-0000-4000-8000-0000000007ad",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
"plan_id": "c0e57121-0000-4000-8000-0000000007ab",
"insurer": "Consorcio",
"plan_name": "Salud Plus",
"plan_active": true,
"policy_number": "P-48213",
"holder_name": null,
"valid_until": "2027-03-31",
"is_primary": true,
"created_at": "2026-10-09T17:45:00.000Z",
"updated_at": "2026-10-09T17:45:00.000Z"
}
],
"total": 1
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
POST /clinic/patients/{id}/insurances
Add a seguro to a patient
The patient’s first seguro is always the primary one; is_primary: true moves the flag from the current primary. 409 when the patient already holds that plan; 400 for a withdrawn plan. Works on any patient source: the seguro is Vitrina’s own record. Requires clinic: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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes |
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
plan_id | uuid | yes | |
policy_number | string | null | — | máx. 60 |
holder_name | string | null | — | máx. 160 |
valid_until | string | null | — | patrón ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ |
is_primary | boolean | — |
curl -X POST https://api.vitrinadev.com/api/v1/clinic/patients/<id>/insurances \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"plan_id": "c0e57121-0000-4000-8000-0000000007ab",
"policy_number": "P-48213",
"valid_until": "2027-03-31"
}'Example response (201)
{
"data": {
"id": "c0e57121-0000-4000-8000-0000000007ad",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
"plan_id": "c0e57121-0000-4000-8000-0000000007ab",
"insurer": "Consorcio",
"plan_name": "Salud Plus",
"plan_active": true,
"policy_number": "P-48213",
"holder_name": null,
"valid_until": "2027-03-31",
"is_primary": true,
"created_at": "2026-10-09T17:45:00.000Z",
"updated_at": "2026-10-09T17:45:00.000Z"
}
}Answers: 201 · 400 · 401 · 403 · 404 · 409 · 429
DELETE /clinic/patients/{id}/insurances/{insuranceId}
Remove a patient’s seguro
Deleting the primary promotes the oldest remaining seguro. Requires clinic: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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes | |
insuranceId | path | uuid | yes |
curl -X DELETE https://api.vitrinadev.com/api/v1/clinic/patients/<id>/insurances/<id> \
-H "Authorization: Bearer $VITRINA_KEY"Answers: 204 · 400 · 401 · 403 · 404 · 409 · 429
PATCH /clinic/patients/{id}/insurances/{insuranceId}
Edit a patient’s seguro
Any field. is_primary: true makes it the primary one; to demote the primary, mark another seguro primary (false is a 400). Requires clinic: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.
| Parameter | In | Type | Required | Constraints |
|---|---|---|---|---|
id | path | uuid | yes | |
insuranceId | path | uuid | yes |
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
plan_id | uuid | — | |
policy_number | string | null | — | máx. 60 |
holder_name | string | null | — | máx. 160 |
valid_until | string | null | — | patrón ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$ |
is_primary | boolean | — |
curl -X PATCH https://api.vitrinadev.com/api/v1/clinic/patients/<id>/insurances/<id> \
-H "Authorization: Bearer $VITRINA_KEY" \
-H "Content-Type: application/json" \
-d '{
"valid_until": "2027-06-30"
}'Example response (200)
{
"data": {
"id": "c0e57121-0000-4000-8000-0000000007ad",
"tenant_id": "a1a1a1a1-0000-4000-8000-000000000001",
"clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
"plan_id": "c0e57121-0000-4000-8000-0000000007ab",
"insurer": "Consorcio",
"plan_name": "Salud Plus",
"plan_active": true,
"policy_number": "P-48213",
"holder_name": null,
"valid_until": "2027-06-30",
"is_primary": true,
"created_at": "2026-10-09T17:45:00.000Z",
"updated_at": "2026-10-09T17:45:00.000Z"
}
}Answers: 200 · 400 · 401 · 403 · 404 · 409 · 429
Insurance reimbursements
The reimbursement request to the insurer per atención, with its documents and states (to send, sent, paid, rejected), the insurer's payments and their reconciliation with the requests they settle, partial included. Insurer money is never counted twice: it is not a Caja payment or an espejo de ingresos row.
Clinic services
What the clinic performs: duration, list price, consent requirements and who may perform each service.