Claims teams and telemedicine platforms lose weeks to lab PDFs, scanned prescriptions and faxed clinical summaries. Zuree reads them and returns normalized, LOINC-coded facts — each one carrying a confidence score and provenance back to the exact source document.
One REST API. Idempotent uploads, signed webhooks, a typed TypeScript SDK, and a FHIR R4 representation of everything it extracts.
{ "jobId": "job_8Kd2", "status": "QUEUED" } {
"type": "document.processing_completed",
"data": {
"documentId": "doc_3Fq9",
"documentType": "LAB_REPORT",
"processingStatus": "PROCESSED"
}
} {
"display": "Hemoglobin",
"coding": { "system": "LOINC", "code": "718-7" },
"valueNumeric": 13.5, "unit": "g/dL",
"interpretation": "LOW",
"confidence": 0.93,
"provenance": { "documentId": "doc_3Fq9",
"method": "AI_TEXT" }
} A single claim or intake can involve a dozen files from a dozen labs, each with its own layout, units and abbreviations. Someone has to read them.
Nurse reviewers and claims adjusters retype values into forms. Throughput is capped by headcount, and the cost per file never falls.
A text dump still needs classifying, coding and unit normalization before a rules engine or model can use it.
If a reviewer can't trace a value back to the page it came from, it can't support a decision that has to be defended.
OCR, template detection, prompt versioning, schema validation, idempotent retries, audit trails. Months of work that isn't your product.
Every stage is idempotent and checkpointed per document. A retry resumes where it stopped — it never duplicates work or re-bills an AI call for a stage that already completed.
The file lands in private object storage keyed by tenant plus a SHA-256 of its bytes. That hash is the document’s identity, so an identical re-upload resolves to the existing document instead of creating a second one.
stage: INGESTION status: ok · 42ms sha256: 9f2c…a71b dedupe: miss
Every processing run is auditable: a stage ledger with timings, tokens, cost and escalation decisions. AI output is treated as untrusted input — it passes schema validation before anything downstream reads it, and repaired JSON is flagged as repaired, never returned as clean.
Provenance is not a footnote — it is a field. Every extracted fact points back to the document, the extraction record, and the method that produced it.
{
"display": "Hemoglobin",
"coding": {
"system": "LOINC",
"code": "718-7",
"display": "Hemoglobin"
},
"valueNumeric": 13.5,
"unit": "g/dL",
"referenceRange": {
"low": 12, "high": 16, "unit": "g/dL",
"text": "12.0 - 16.0"
},
"interpretation": "LOW",
"observedAt": "2026-07-01",
"confidence": 0.93,
"provenance": {
"documentId": "doc_3Fq9",
"extractionId": "ext_7Bm2",
"method": "AI_TEXT",
"confidence": 0.93
}
} curl -sX POST "$ZUREE_BASE_URL/v1/patients" \
-H "Authorization: Bearer $ZUREE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"pseudonym":"ext-user-42"}'
# → {"id":"<patientId>",
# "pseudonym":"ext-user-42",
# "createdAt":"2026-07-01T09:12:04.000Z"} import { ZureeClient } from '@zuree/sdk';
const zuree = new ZureeClient({
apiKey: process.env.ZUREE_API_KEY!,
baseUrl: process.env.ZUREE_BASE_URL!,
});
const patient = await zuree.patients.create({
pseudonym: 'ext-user-42',
}); CONTENT=$(base64 -i lab-report.pdf)
curl -sX POST "$ZUREE_BASE_URL/v1/documents" \
-H "Authorization: Bearer $ZUREE_API_KEY" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: $(uuidgen)" \
-d "{\"patientId\":\"$PATIENT_ID\",
\"filename\":\"lab-report.pdf\",
\"mimeType\":\"application/pdf\",
\"content\":\"$CONTENT\"}"
# → {"document":{"id":"<documentId>",
# "status":"SECURITY_CHECKED"},
# "duplicate":false} import { readFile } from 'node:fs/promises';
import { randomUUID } from 'node:crypto';
const bytes = await readFile('lab-report.pdf');
const { document } = await zuree.documents.create(
{
patientId: patient.id,
filename: 'lab-report.pdf',
mimeType: 'application/pdf',
content: bytes.toString('base64'),
},
{ idempotencyKey: randomUUID() },
); curl -sX POST \
"$ZUREE_BASE_URL/v1/documents/$DOCUMENT_ID/process" \
-H "Authorization: Bearer $ZUREE_API_KEY"
# → 202 {"jobId":"<jobId>",
# "status":"QUEUED",
# "attempts":0} await zuree.documents.process(document.id);
let s = await zuree.documents.status(document.id);
while (s.status === 'PROCESSING') {
await new Promise((r) => setTimeout(r, 2000));
s = await zuree.documents.status(document.id);
} curl -sX POST "$ZUREE_BASE_URL/v1/webhooks" \
-H "Authorization: Bearer $ZUREE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://your-app.example/hooks/zuree",
"events":["document.processing_completed",
"document.processing_failed"]}'
# → {"id":"whe_…","secret":"whsec_…"} import { verifyWebhookSignature } from '@zuree/sdk';
app.post('/hooks/zuree', async (req, res) => {
const raw = await readRawBody(req);
const check = verifyWebhookSignature({
payload: raw,
signatureHeader: req.headers['zuree-webhook-signature'],
secret: process.env.ZUREE_WEBHOOK_SECRET!,
});
if (!check.ok) return res.status(401).end();
const event = JSON.parse(raw);
res.status(200).end();
}); curl -s \
"$ZUREE_BASE_URL/v1/patients/$PID/observations?limit=50" \
-H "Authorization: Bearer $ZUREE_API_KEY"
# → { "items": [ { "display": "Hemoglobin",
# "coding": {"system":"LOINC","code":"718-7"},
# "valueNumeric": 13.5, "unit": "g/dL",
# "interpretation": "LOW", "confidence": 0.93,
# "provenance": {…} } ],
# "nextCursor": "b2Zmc2V0OjUw" } for await (const obs of zuree.clinical.observationsAll(patient.id)) {
console.log(
obs.display,
obs.valueNumeric ?? obs.valueText,
obs.unit ?? '',
`(${obs.confidence})`,
);
}
for await (const e of zuree.clinical.timelineAll(patient.id)) {
console.log(e.date ?? '(undated)', e.kind);
} Send an Idempotency-Key and a retry can’t duplicate. Identical bytes dedupe automatically.
HMAC-signed, at-least-once delivery with exponential backoff and a per-endpoint delivery log.
429 with Retry-After. The SDK retries automatically, honoring it.
Live spec at /v1/openapi.json. Clinical data also exports as FHIR R4.
Feed claim attachments straight into your rules engine. Coded observations, medications and procedures arrive with confidence scores, so you can auto-approve the clean ones and route only the ambiguous files to a human.
Let patients upload whatever they have during intake. Zuree returns a merged chronological timeline — labs, medications, conditions, procedures, encounters — so the consult starts with context instead of a document viewer.
Medical evidence from a hundred different labs normalizes to the same coded model, so risk scoring compares like with like. LOINC where a code exists, an explicit Zuree LOCAL code where it doesn’t — never a silent guess.
You could build OCR, template detection, prompt versioning, schema validation and an audit trail. Or you could install the SDK this afternoon and spend the quarter on the product your users actually asked for.
Zuree Mobile is a live consumer product running entirely on the endpoints documented on this page — the same pseudonymous patient model, the same ten-stage pipeline, the same coded output. No private endpoints, no privileged path.
That makes it our reference implementation and our standing accuracy benchmark: unfamiliar lab layouts hit it every day, and a regression surfaces in real records before it can reach a customer’s tenant.
zuree.app (iOS / Android)
│
└─ POST /v1/documents
POST /v1/documents/:id/process
GET /v1/patients/:id/timeline
│
└─ the same V1 API on this page You identify patients with an opaque reference you control. Zuree never needs a real-world identifier to process a document.
Zuree makes no regulatory compliance claim — not GDPR, not HIPAA, not any other framework. The controls beside this are the technical mechanisms we implement and will walk your security team through. Determining lawful bases, retention periods and erasure obligations in your jurisdiction remains yours. We’d rather tell you that up front than in diligence.
Logs, metrics, analytics, error trackers, webhook payloads and audit records carry opaque IDs, codes and counts — never document content.
Tenant identity resolves server-side from your API key. A tenant_id is never accepted from a request body.
Object storage buckets are private; signed URLs expire in minutes. Uploads are malware-scanned and content type is verified from the bytes.
Every extraction records which provider, which exact model, which prompt version and which pipeline version produced it — readable via the API.
Deleting a document clears it from the database, object storage, processing queue and temporary files — leaving an audit record of IDs and counts, not content.
Indefinite by default — Zuree never deletes what you didn’t ask it to. Enable a per-tenant document-age window and expired files purge through the same path.
Scope discipline is part of the security posture: Zuree transcribes documents into structured data. It does not diagnose, interpret findings, read imaging, recommend treatment, or act as clinical decision support — and we decline feature requests that cross that line.
A document is one file you send to /process. Deduplicated re-uploads and resumed retries are never billed twice. Overage is metered per document, so a spike costs money — not an upgrade conversation.
Get one workflow into production without a procurement cycle.
For teams running claims intake or patient onboarding every day.
For insurers and platforms where document volume is the business.
All three V1 document types, LOINC coding, provenance, confidence, webhooks, the OpenAPI spec, the TypeScript SDK, FHIR R4 export and audited deletion. No feature is paywalled — only volume and support differ.
Duplicate uploads (identical bytes), resumed retries of a checkpointed stage, documents returned as UNSUPPORTED, and every read of data you already have.
A free sandbox tenant with 100 documents comes with every technical evaluation, so you can benchmark accuracy on your own corpus before signing anything.
Drag to your expected monthly document count. We pick the cheapest tier for that volume, including overage.
Estimates only, excluding tax. Annual billing applies a 15% discount on the platform fee; overage stays at the tier rate. Committed volumes above 120,000 documents per month are priced individually.
Something not covered? Bring it to the technical call — an engineer is on it, not just a rep.
Laboratory reports, prescriptions, and medical reports / clinical summaries. A document that Zuree recognizes but that falls outside that scope returns status UNSUPPORTED rather than a guessed extraction — and isn’t billed. Additional types are a roadmap conversation, not a silent expansion.
No. Zuree transcribes and normalizes what the document says. It is not a diagnostic, medical-advice, radiology-interpretation, treatment-recommendation or clinical-decision-support system. The interpretation field on an observation reflects the flag printed on the source report against its own reference range — it is transcription, not judgement.
AI output is treated as untrusted input. Every response is schema-validated before anything downstream reads it. Raw responses are kept immutably, separate from the normalized facts, so an extraction can always be re-derived and audited. JSON that had to be repaired or salvaged is flagged as such — it is never returned as clean. And no field silently defaults: a missing confidence stays missing rather than becoming a plausible number.
Yes — extraction requires it. Which provider and which exact model handled a given document is recorded on the extraction record and readable through GET /v1/documents/{id}/extraction, alongside prompt and pipeline versions. Providers sit behind an internal interface, so the mix can change; the attribution on each record tells you exactly what processed what. Provider handling is governed by their contract, which we’ll share in diligence.
Numeric limits are set per deployment and plan, not fixed in the API contract — your tenant’s are stated on your account. The mechanism is stable regardless: a 429 with Retry-After, which the SDK honors automatically with backoff and jitter. Bulk processing queues against a concurrency budget instead of being rejected, so submitting a thousand documents at once is fine.
Both. A complete portable JSON export per patient includes per-document provider accounting, and the clinical data is also available as FHIR R4. Deletion is explicit and tenant-initiated — DELETE /v1/documents/{id} removes a document and its derived data across the database, object storage, queue and temporary files, leaving an audit record of who and when, never of what.
One file that completes a processing run. Re-uploading identical bytes returns the existing document with "duplicate": true and isn’t billed again. A retry that resumes a checkpointed stage doesn’t re-bill the AI call for a stage that already finished. Reads of data you already hold are unmetered.
Every endpoint and field, with curl and SDK examples side by side.
Read the docs →Typed TypeScript client with auto-pagination, retry and webhook verification.
Generate a client in your language from the running deployment's own spec.
The same clinical model, rendered as FHIR resources for your existing stack.
See the mapping →Forty-five minutes with an engineer, not a pitch. We run your real files through the pipeline, show you the extraction records and the provenance, and tell you plainly where it struggles.
Sandbox tenant with 100 free documents. No card, no procurement.