VitrinaAPI

Presupuestar un plan y cerrar caja

Proponer un plan, cotizarlo con folio y cuadrar la caja del turno.

ClínicasSolo en los workspaces de clínicas.

POST /clinic/treatment-plans propone el tratamiento, POST /clinic/budgets lo cotiza con folio y POST /clinic/cash-sessions abre el turno que recibe el dinero. El paciente acepta el presupuesto, y eso abre lo que debe.

Las lecturas piden clinic_money:read y las escrituras clinic_money:write. Abrir y cerrar la caja necesita además una persona: un token personal sirve, una API key no (Tokens personales).

El plan de tratamiento

Un plan propone qué prestaciones, cuántas veces y en qué orden.

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 mueve cada fase a scheduled, performed o cancelled. Pasar a scheduled exige nombrar la cita asociada. GET /clinic/patients/{id}/treatment-progress cuenta las citas realizadas y las sesiones consumidas: reporta lo ejecutado y nunca lo prometido.

El presupuesto y su 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 }
    ]
  }'

Un folio es una secuencia legal

El presupuesto toma su folio (display_id, «E-47») al crearse, y la secuencia no tiene huecos: un borrador descartado deja su número gastado. Manda siempre una Idempotency-Key; un reintento sin ella gasta otro folio.

Cada línea congela su precio al agregarse: el precio cotizado es el que se cobra, aunque el arancel cambie mañana. En draft se edita, se agregan y se quitan líneas, o se descarta entero. Un presupuesto enviado se anula, con su motivo, y nunca se borra.

Enviarlo

POST /clinic/budgets/{id}/send se lo manda al paciente por su canal, con un enlace propio para aceptarlo o rechazarlo. La respuesta dice por dónde salió (delivered), o que la clínica no tenía cómo alcanzarlo.

Hay tres finales, cada uno con su evento: aceptado, rechazado o anulado. Aceptar abre el dinero: crea las obligaciones del paciente, con sus cuotas, agrupadas bajo un obligation_group_id.

La caja del turno

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

Una sesión de caja es un turno en una sucursal. Se abre con el fondo inicial, recibe los pagos del día y se cierra contra un conteo:

{
  "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 es lo que había menos lo que el sistema esperaba. Si no es cero, el cierre pide un motivo, y POST /clinic/cash-sessions/{id}/reconcile es la firma de quien revisó el arqueo.

Dónde caen los cobros

El dinero vive en el ledger de cobros de la plataforma, el mismo de cualquier vertical. Obligaciones, pagos e imputaciones están en Cobros y pagos.

Una cita con política de abono abre su obligación sola, y un presupuesto aceptado abre las suyas. GET /contacts/{id}/ledger responde si este paciente debe algo.

Eventos

EventoCuándo
clinic_budget.createdSe creó el presupuesto, y se gastó un folio
clinic_budget.sentSalió al paciente, con su enlace
clinic_budget.acceptedAceptado; trae el obligation_group_id que abrió
clinic_budget.rejected · .voidedEl paciente dijo que no, o la clínica lo anuló con motivo
clinic_cash_session.opened · .closedSe abrió el turno, o se cerró contra un conteo (con la diferencia)

Los eventos de presupuesto llevan folio, estado y totales, nunca las líneas. Quien pueda leerlo lo lee con su credencial, en la url del aviso.

En esta página