Upload flow
Upload an exam in 3 steps
Uploading an exam is a 3-step flow. Files go directly to Cloudflare R2 with presigned URLs (they do not pass through our servers), so it is fast even with 500 MB+ scans.
Step 1 — Create the exam
Send patient metadata and the file list (name + size in bytes). You receive an exam_id and presigned URLs (valid for 15 minutes).
POST /api/v1/exams
{
"name": "CBCT mandíbula",
"patient_name": "Juan Pérez",
"files": [
{ "name": "ct_001.dcm", "size": 524288 }
]
}Step 2 — Upload files to R2
For each presigned URL, do a PUT with the file binary content. R2 responds 200 OK if the upload succeeded. No additional auth needed: the URL is already signed.
PUT https://r2.cloudflarestorage.com/.../ct_001.dcm
Content-Type: application/dicom
<bytes>Step 3 — Confirm
Once all files are uploaded, call /confirm to mark the exam as ready. You receive share_url (branded link) and viewer_url (direct 3D viewer).
POST /api/v1/exams/{exam_id}/confirm
→ {
"ok": true,
"exam_id": "...",
"status": "ready",
"share_url": "https://cbcthub.com/share/...",
"viewer_url": "https://cbcthub.com/viewer/..."
}Flow diagram
TU SISTEMA CBCTHub API Cloudflare R2
│ │ │
├──POST /v1/exams────────►│ │
│ │ │
│◄────exam_id, upload_urls┤ │
│ │
├──PUT ct_001.dcm ────────────────────────────────►│
├──PUT ct_002.dcm ────────────────────────────────►│
│◄───── 200 OK ───────────────────────────────────┤
│ │
├──POST /v1/exams/{id}/confirm ►│ │
│◄────share_url, viewer_url─────┤ │ℹ Idempotency
What if upload takes longer than 15 minutes?
Presigned URLs expire after 15 minutes. If your client did not finish uploading in time, call POST /api/v1/exams again to regenerate URLs. The old exam_id stays in status uploading until you delete it.