VitrinaAPI

Quote a plan and close the till

Propose a plan, quote it under a folio and balance the shift's till.

ClinicsOnly in clinic workspaces.

POST /clinic/treatment-plans proposes the treatment, POST /clinic/budgets quotes it under a folio and POST /clinic/cash-sessions opens the shift that takes the money. The patient accepts the presupuesto, and that opens what they owe.

Reads need clinic_money:read and writes clinic_money:write. Opening and closing the till also needs a person: a personal token will do, an API key won't (Personal tokens).

The treatment plan

A plan proposes which services, how many times and in what order.

curl -X POST https://api.vitrinadev.com/api/v1/clinic/treatment-plans \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
    "name": "Ortodoncia fija superior e inferior",
    "diagnosis": "Apiñamiento anterosuperior moderado",
    "items": [
      { "clinic_service_id": "4cf5bc59-0000-4000-8000-000000000001", "phase": 1, "quantity": 4 }
    ]
  }'

POST /clinic/treatment-plan-items/{id}/status moves each phase to scheduled, performed or cancelled. Moving to scheduled demands naming the appointment it belongs to. GET /clinic/patients/{id}/treatment-progress counts appointments held and pack sessions used: it reports what was done and never what was promised.

The presupuesto and its folio

curl -X POST https://api.vitrinadev.com/api/v1/clinic/budgets \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: presupuesto-mjfuentes-2026-09" \
  -d '{
    "clinic_patient_id": "b1b0b8de-0000-4000-8000-000000000001",
    "treatment_plan_id": "1ccffee2-0000-4000-8000-000000000001",
    "valid_until": "2026-12-31",
    "installments": 3,
    "items": [
      { "clinic_service_id": "4cf5bc59-0000-4000-8000-000000000001", "quantity": 4, "phase": 1 }
    ]
  }'

A folio is a legal sequence

A presupuesto takes its folio (display_id, "E-47") when it is created, and the sequence has no gaps: a draft thrown away leaves its number spent. Always send an Idempotency-Key; a retry without one spends another folio.

Every line freezes its price as it's added: the price quoted is the price charged, even if the price list moves tomorrow. A draft can be edited, gain and lose lines, or be thrown away. A sent presupuesto is voided, with its reason, and never deleted.

Sending it

POST /clinic/budgets/{id}/send sends it to the patient over their channel, with a link of their own to accept or decline. The answer says how it left (delivered), or that the clinic had no way to reach them.

There are three endings, each with its event: accepted, rejected or voided. Acceptance opens the money: it creates the patient's obligations, instalments included, grouped under an obligation_group_id.

The shift at the till

curl -X POST https://api.vitrinadev.com/api/v1/clinic/cash-sessions \
  -H "Authorization: Bearer $VITRINA_PERSONAL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{ "location_id": "b1b1b1b1-0000-4000-8000-000000000002", "opening_float_clp": 30000 }'

A cash session is one shift at one branch. It opens with a float, takes the day's payments and closes against a count:

{
  "data": {
    "id": "d1d832c4-0000-4000-8000-000000000001",
    "location_id": "b1b1b1b1-0000-4000-8000-000000000002",
    "opening_float_clp": 30000,
    "expected_clp": 30000,
    "counted_clp": 50000,
    "difference_clp": 20000,
    "difference_reason": "Vuelto de un pago en efectivo",
    "status": "closed"
  }
}

difference_clp is what the drawer held minus what the ledger expected. When it isn't zero the close demands a reason, and POST /clinic/cash-sessions/{id}/reconcile signs off the count.

Where the charges land

The money lives in the platform's charges ledger, the same one every vertical uses. Obligations, payments and allocations are in Charges and payments.

An appointment with a deposit policy opens its own obligation, and an accepted presupuesto opens its own. GET /contacts/{id}/ledger answers whether this patient owes anything.

Events

EventWhen
clinic_budget.createdThe presupuesto was created, and a folio was spent
clinic_budget.sentIt went to the patient, with their link
clinic_budget.acceptedAccepted; carries the obligation_group_id it opened
clinic_budget.rejected · .voidedThe patient said no, or the clinic voided it with a reason
clinic_cash_session.opened · .closedThe shift opened, or closed against a count (with the difference)

Budget events carry the folio, the state and the totals, never the lines. Whoever may read it reads it with their own credential, at the url the notice carries.

On this page