VitrinaAPI

Seguros de la clínica

Los seguros del paciente (varios, uno principal), la tabla de cobertura por plan y prestación, y la cobertura estimada y el copago en el presupuesto y en el estado de cuenta, también en PDF. La cobertura nunca es un descuento: los precios y convenios no cambian.

Beta
Puede cambiar en cualquier momento, con una entrada en el changelog y aviso a quienes la llamaron recientemente — ver versionado.

Descarga la proyección completa de la API pública: openapi.json.

MétodoRutaQué hace
GET/clinic/budgets/{id}/coverageCobertura and copago of a presupuesto
GET/clinic/insurance/plansList the insurer plans
POST/clinic/insurance/plansAdd an insurer plan
PATCH/clinic/insurance/plans/{id}Rename or withdraw an insurer plan
GET/clinic/insurance/plans/{id}/coverageRead a plan’s coverage table
PUT/clinic/insurance/plans/{id}/coverageSet one coverage rule
DELETE/clinic/insurance/plans/{id}/coverage/{ruleId}Remove one coverage rule
GET/clinic/patients/{id}/insurance-statementEstado de cuenta with the seguro’s cobertura
GET/clinic/patients/{id}/insurance-statement/renderEstado de cuenta with the seguro, as a PDF
GET/clinic/patients/{id}/insurancesList a patient’s seguros
POST/clinic/patients/{id}/insurancesAdd 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.

ParámetroEnTipoObligatorioRestricciones
idpathanysí
insurance_idqueryuuidno
curl https://api.vitrinadev.com/api/v1/clinic/budgets/<id>/coverage \
  -H "Authorization: Bearer $VITRINA_KEY"

Ejemplo de respuesta (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
  }
}

Responde: 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.

ParámetroEnTipoObligatorioRestricciones
activequerytrue \falseno
curl https://api.vitrinadev.com/api/v1/clinic/insurance/plans \
  -H "Authorization: Bearer $VITRINA_KEY"

Ejemplo de respuesta (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
  }
}

Responde: 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.

Cuerpo

CampoTipoObligatorioRestricciones
insurerstringsímín. 1, máx. 120
namestringsí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"
  }'

Ejemplo de respuesta (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"
  }
}

Responde: 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.

ParámetroEnTipoObligatorioRestricciones
idpathuuidsí

Cuerpo

CampoTipoObligatorioRestricciones
insurerstring—mín. 1, máx. 120
namestring—mín. 1, máx. 120
activeboolean—
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
  }'

Ejemplo de respuesta (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"
  }
}

Responde: 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.

ParámetroEnTipoObligatorioRestricciones
idpathuuidsí
curl https://api.vitrinadev.com/api/v1/clinic/insurance/plans/<id>/coverage \
  -H "Authorization: Bearer $VITRINA_KEY"

Ejemplo de respuesta (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
  }
}

Responde: 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.

ParámetroEnTipoObligatorioRestricciones
idpathuuidsí

Cuerpo

CampoTipoObligatorioRestricciones
clinic_service_idstring | null—
kindpercent \amountsí
percentnumber | null—≥ 0, ≤ 100
amount_clpinteger | null—≥ 0, ≤ 1000000000
cap_clpinteger | 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
  }'

Ejemplo de respuesta (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
  }
}

Responde: 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.

ParámetroEnTipoObligatorioRestricciones
idpathuuidsí
ruleIdpathuuidsí
curl -X DELETE https://api.vitrinadev.com/api/v1/clinic/insurance/plans/<id>/coverage/<id> \
  -H "Authorization: Bearer $VITRINA_KEY"

Responde: 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.

ParámetroEnTipoObligatorioRestricciones
idpathuuidsí
insurance_idqueryuuidno
curl https://api.vitrinadev.com/api/v1/clinic/patients/<id>/insurance-statement \
  -H "Authorization: Bearer $VITRINA_KEY"

Ejemplo de respuesta (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
    }
  }
}

Responde: 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.

ParámetroEnTipoObligatorioRestricciones
idpathuuidsí
insurance_idqueryuuidno
curl https://api.vitrinadev.com/api/v1/clinic/patients/<id>/insurance-statement/render \
  -H "Authorization: Bearer $VITRINA_KEY"

Responde: 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.

ParámetroEnTipoObligatorioRestricciones
idpathuuidsí
curl https://api.vitrinadev.com/api/v1/clinic/patients/<id>/insurances \
  -H "Authorization: Bearer $VITRINA_KEY"

Ejemplo de respuesta (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
  }
}

Responde: 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.

ParámetroEnTipoObligatorioRestricciones
idpathuuidsí

Cuerpo

CampoTipoObligatorioRestricciones
plan_iduuidsí
policy_numberstring | null—máx. 60
holder_namestring | null—máx. 160
valid_untilstring | null—patrón ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
is_primaryboolean—
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"
  }'

Ejemplo de respuesta (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"
  }
}

Responde: 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.

ParámetroEnTipoObligatorioRestricciones
idpathuuidsí
insuranceIdpathuuidsí
curl -X DELETE https://api.vitrinadev.com/api/v1/clinic/patients/<id>/insurances/<id> \
  -H "Authorization: Bearer $VITRINA_KEY"

Responde: 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.

ParámetroEnTipoObligatorioRestricciones
idpathuuidsí
insuranceIdpathuuidsí

Cuerpo

CampoTipoObligatorioRestricciones
plan_iduuid—
policy_numberstring | null—máx. 60
holder_namestring | null—máx. 160
valid_untilstring | null—patrón ^\d{4}-(0[1-9]|1[0-2])-(0[1-9]|[12]\d|3[01])$
is_primaryboolean—
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"
  }'

Ejemplo de respuesta (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"
  }
}

Responde: 200 · 400 · 401 · 403 · 404 · 409 · 429

En esta página