Retrieve results
Receive the finished report by callback, including findings and key images with their DICOM slice references.
Pass callback_url when you submit a study. When the read finishes, we POST the study object to your HTTPS endpoint with event: "study.completed". The payload includes the report, its findings and the key images. Failed reads notify too, with status: "error" and report: null.
Receive the callback
curl -s -X POST "https://api.vitalview.ai/v1/studies" \
-H "X-API-Key: $KEY" \
-F "file=@study.zip" \
-F "scan_type=ct_brain" \
-F "callback_url=https://your-host.example/vitalview-hook"
Your endpoint must use HTTPS, contain no embedded credentials, and resolve to a public address. The destination is checked at delivery; an unusable callback URL does not reject the study submission. Return a 2xx response after accepting the notification. Redirects are refused. Connection errors and 5xx responses are retried up to three attempts; 4xx responses are not retried.
Verify X-VitalView-Signature against the exact request bytes before accepting the payload. The signing secret is the SHA-256 hex digest of the API key used to submit the study:
import hashlib
import hmac
secret = hashlib.sha256(api_key.encode()).hexdigest()
expected = "sha256=" + hmac.new(secret.encode(), raw_body, hashlib.sha256).hexdigest()
valid = hmac.compare_digest(expected, signature_header)
X-VitalView-Event is study.completed. The callback body has the same fields as the study response below, plus event.
Fetch a study when needed
You can fetch the study directly to inspect progress or recover the result after a missed callback:
curl -s "https://api.vitalview.ai/v1/studies/a1b2c3d4" -H "X-API-Key: $KEY"
While reading:
{
"study_id": "a1b2c3d4",
"status": "processing",
"step": "reading",
"slices": 149,
"slices_read": 92,
"scan_type": "ct_brain",
"quality": "smart",
"patient": { "name": "DOE^JANE", "dob": "1980-01-01", "gender": "F" },
"clinical_indication": "Fall with loss of consciousness",
"created_at": "2026-07-05T09:12:44Z",
"started_at": "2026-07-05T09:14:02Z",
"completed_at": null,
"error": null,
"report": null
}
step is preparing, reading or report; slices and slices_read appear once the read has started.
The report
Once status is complete, report is filled in:
{
"study_id": "a1b2c3d4",
"status": "complete",
"...": "...",
"completed_at": "2026-07-05T09:16:40Z",
"report": {
"markdown": "# CT HEAD\n\n## CLINICAL HISTORY\nFall with loss of consciousness.\n\n## FINDINGS\nRight frontal scalp swelling [Fig. 1]. ...",
"findings": "Right frontal scalp swelling [Fig. 1]. No fracture...",
"impression": "1. Right frontal scalp swelling.",
"sections": [
{ "id": "section-1", "text": "Right frontal scalp swelling [Fig. 1].", "figures": [1] },
{ "id": "section-2", "text": "No acute intracranial haemorrhage.", "figures": [] }
],
"figures": [
{
"number": 1,
"caption": "Right frontal scalp swelling",
"url": "https://cdn.vitalview.ai/report-assets/....png",
"location": {
"series_uid": "1.2.840.113619.2.55...",
"plane": "axial",
"sop_instance_uid": "1.2.840.113619.2.55...95",
"instance_number": 95,
"point_mm": [55.73, 45.63, 36.5],
"marks": [
{ "type": "line", "role": "finding", "start_mm": [52.1, 40.2, 36.5], "end_mm": [59.3, 51.0, 36.5] },
{ "type": "line", "role": "mirror", "start_mm": [-52.4, 40.0, 36.5], "end_mm": [-56.6, 47.1, 36.5] }
]
}
}
],
"unavailable_figure_numbers": [],
"html_url": "https://api.vitalview.ai/v1/studies/a1b2c3d4/report.html",
"generated_at": "2026-07-05T09:16:31Z",
"completion_status": "complete",
"review_required": true
}
}
| Field | Meaning |
|---|---|
markdown | The draft report with the standard sections. Load it into your report editor for the radiologist to edit and sign. Figures are cited in the text as [Fig. N] |
findings, impression | The two report sections as plain text |
sections | The findings split into paragraphs, in report order, with the figure numbers each cites. These are sections of the report, not a list of abnormalities |
figures | The key images the text cites. url is permanent and needs no API key, so it can go straight into an <img> |
unavailable_figure_numbers | Figures the text cites whose image could not be served. Numbers are never re-sequenced |
html_url | The same report as a standalone HTML page with its figures embedded. Fetch it with your API key |
completion_status | complete, incomplete or failed: how the read itself ended |
review_required | Always true. This is a draft for a clinician to review and sign |
Opening a figure in your viewer
Each figure's location says where it sits in the study, so a radiologist can jump to the same image in your PACS:
series_uidis the DICOM SeriesInstanceUID the figure was taken from.sop_instance_uidandinstance_numbername the slice the figure shows. They arenullfor a sagittal or coronal reformat, which is built from every slice.point_mmis the centre of the marked finding in DICOM patient coordinates (LPS, millimetres), ornullwhen the figure carries no mark.marksare the shapes drawn on the figure, in the same coordinates, so your viewer can draw them on the DICOM:{"type": "circle", "center_mm", "radius_mm"},{"type": "line", "start_mm", "end_mm"}or{"type": "outline", "points_mm"}.roleisfindingfor the finding itself andmirrorfor the same measurement on the opposite side, drawn for comparison; it isnullon reads that did not record it. Empty when the figure carries no mark.
location itself is null when the read did not record where a figure came from.
Report as HTML
curl -s "https://api.vitalview.ai/v1/studies/a1b2c3d4/report.html" -H "X-API-Key: $KEY" -o report.html
Returns text/html, ready to display or print. Before the read completes it answers 404 results_not_ready.
Listing studies
GET /studies lists your studies, newest first, with study_id, status, scan_type, patient and created_at. It accepts status and limit query parameters.
Next: Errors & status codes