VitrinaAPI

Add documents to a patient record

Upload documents to a record and answer access and erasure requests.

ClinicsOnly in clinic workspaces.

POST /clinic/patients/{id}/documents hangs a file off a record and GET /clinic/documents/{id}/content downloads its bytes. Every document carries a date until which it must be kept. Answering the person who asks for their data, or for its erasure, is a legal obligation with deadlines.

Sensitive, and with an extra rule about the bytes

It demands clinic_record:read, or clinic_record:write to write, on top of the clinic scope. Every read lands in the access log, and a connected app receives 403 CONNECTED_APP_SENSITIVE_DATA. The file download doesn't go to a connected app either, even when the clinic has allowed names (Personal and health data).

What hangs off a record

curl "https://api.vitrinadev.com/api/v1/clinic/patients/$PACIENTE/documents" \
  -H "Authorization: Bearer $VITRINA_KEY"
{
  "data": {
    "data": [
      {
        "id": "99999999-0000-4000-8000-000000000001",
        "clinic_patient_id": "12121212-0000-4000-8000-000000000001",
        "encounter_id": "44444444-0000-4000-8000-000000000001",
        "kind": "imagen",
        "title": "Radiografía panorámica",
        "mime_type": "application/pdf",
        "size_bytes": 182344,
        "sensitivity": "phi",
        "uploaded_source": "staff",
        "retention_until": "2041-09-22",
        "purged_at": null,
        "purge_reason": null,
        "created_at": "2026-09-22T21:53:03.510Z"
      }
    ],
    "total": 1,
    "page": 1,
    "limit": 50
  }
}
  • kind says what it is, and with that its retention deadline: examen, imagen, informe, receta, indicaciones, consentimiento, presupuesto, boleta, certificado, otro.
  • sensitivity splits the clinical (phi) from the administrative. A receipt and an X-ray share a list without sharing treatment.
  • uploaded_source says who uploaded it: staff, the patient from their own link, an agent, an import or the system.
  • retention_until comes from the kind and the clinic's policy (Retention).
  • purged_at and purge_reason are the tombstone. A deleted document doesn't leave the list: what was there and why it no longer is stays behind.

POST /clinic/documents/{id}/delete removes it before its deadline, and therefore demands a reason.

The patient's rights

Ley 21.719 gives a person the right to take their data with them and to ask for it to be erased. Both are requests with a status: a whole record has to be assembled, and an erasure has to be weighed against the legal deadline.

curl -X POST "https://api.vitrinadev.com/api/v1/clinic/patients/$PACIENTE/export" \
  -H "Authorization: Bearer $VITRINA_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "reason": "Solicitud de acceso de la paciente, recibida en la recepción el 2026-09-22" }'

GET /clinic/privacy-requests lists the requests with their status, and GET /clinic/privacy-requests/{id}/download fetches the archive once the export is ready. The reason is mandatory on both routes: who asked for what and when is part of showing it was answered in time.

Erasure

POST /clinic/patients/{id}/erase requests erasure, and what can go is bounded by the retention floor. What the law requires to be kept isn't deleted because somebody asks. The response says what was deleted and what is kept, with its date.

Events

EventWhen
clinic_document.uploadedA document entered a record
clinic_document.deletedIt was deleted before its deadline, with its reason
clinic_privacy_request.completedAn export or an erasure is ready

All three arrive as a notice, with data_omitted: "sensitive". An event never carries the file, nor a link that would hand it over without a credential. It carries the id, and whoever holds the scope downloads it with theirs. That download is logged too.

On this page