GET /api/v1/appointments/{id}/results and include clinical biomarker results, genetic biomarker results, and downloadable lab report documents.
Results status
The top-levelstatus field on the results response indicates overall processing progress:
Individual results within the response have their own per-result status (see below), so you can display partial results while the overall status is still
in_progress.
To learn when results change, subscribe to webhooks. appointment.results.updated fires on every change of the results body, and appointment.results.completed fires when the top-level status moves into completed. Home kit orders send the same events with the home_kit_order. prefix. Each event carries the results URL to fetch. You can still poll this endpoint to reconcile.
The submissions array breaks the top-level status down per laboratory requisition. A draw that spans several tubes or several laboratories has several entries, each with the lab_code (tube barcode) it was filed under and its own in_progress / completed / fault status. A fault entry was rejected or abandoned at the lab and will never report: the sample was often moved to another laboratory, which then files its own entry. The top-level status is completed when every entry has closed and at least one reported. Every received result and every document carries the same lab_code, so you can tell which tube a value came from.
Clinical results
Clinical results represent standard blood biomarker measurements — things like Vitamin D levels, cholesterol, thyroid hormones, and so on. Each clinical result includes:id— the lab result row identifier. It stays the same when the lab corrects that row, so use it to upsert.nullfor aplannedresult.biomarker_nameandcategory— what was measured and its grouping (e.g., Vitamins, Hormones).lab_code— the lab code (tube barcode) the result was filed under, one of the order’s lab codes.nullfor aplannedresult and for results the lab reported without a code.valueandvalue_operator— the effective measurement. The operator iseq(equals) for exact values, orlt/gtwhen the lab reports a value below or above the measurable range.unit— the measurement unit (e.g., ng/mL, µIU/mL).reference_range_lab— normal and optimal min/max bounds as reported by the lab for this result, converted onto the same scale asvalue. A bound the lab leaves open isnull, so a one-sided interval such as< 50arrives asnormal_min: null, normal_max: 50. Each result carries the interval it was measured against, so a patient with results across several draws or labs gets the right one per result.reference_range_lab_absent_reason— whyreference_range_labisnull.nullwhen the range is present, and on aplannedresult. See When there is no lab range.reference_range_aniva— Aniva-curated reference ranges adjusted for age, sex, and pregnancy status, on the same scale asvalue.nullwhen your key lacks theaniva_reference_ranges_viewscope, or when Aniva has no range of its own for this biomarker.tested_at— the date the test was performed.comment— free-text annotation from the lab on this specific result (e.g., reference-range guidance, sample-quality warnings).nullwhen the lab did not attach one.status_reason— why afaultorundeliverableresult is unusable.nullfor every other status. Distinct fromcomment, which is the lab’s own note and is often empty on faulted results.lab_reported— the performing lab’s own report line, verbatim and unconverted. See below.
Normalized values versus the lab’s own line
value, unit and reference_range_lab are normalized: we convert every measurement onto the biomarker’s canonical unit and report it under our own biomarker name, so the same analyte is comparable across labs and over time. That is what you want for trending and thresholds, and it is not what a reviewing doctor sees on the lab’s PDF — alkaline phosphatase printed as 48 U/l (40 - 129) reaches you as 0.8 µkat/L.
lab_reported carries that printed line alongside it: the lab’s analyte name and code, the value and unit as printed, the reference interval both as text (< 50, > 55, 40 - 129) and as the lab’s own unconverted bounds, plus its abnormal flag, result status and note.
Use lab_reported when a human is reconciling your data against the lab’s report, and the canonical fields for everything computed. Only fields the lab actually sent are populated; nothing in lab_reported is inferred, defaulted or converted, and the whole object is null when we hold no raw record for a result.
When there is no lab range
Whenreference_range_lab is null, reference_range_lab_absent_reason tells you why:
Some labs print a target or a risk tier in place of a reference range, for example
Ziel: <200. >240 hoch or <5.7 neg >=6.5 pos. These do not go into reference_range_lab, so its
bounds are null and the reason is lab_text_only. Show the printed text verbatim.
A one-sided range such as < 20 is a range. It arrives in reference_range_lab with one bound
null, and the reason is null. Keep the open side open when you show it.
Clinical result statuses
Genetic results
Genetic results represent gene-level findings from DNA analysis. Each result corresponds to a gene (e.g., APOE, MTHFR) and includes:id— the lab result row identifier. It stays the same when the lab corrects that row, so use it to upsert.nullfor aplannedresult.gene— the gene symbol.lab_code— the lab code (tube barcode) the result was filed under.nullfor aplannedresult and for results the lab reported without a code.genotype— the detected genotype (e.g., E3/E4).clinical_significance— an ACMG-based classification of the finding.risk_description— a human-readable explanation of what the genotype means.comment— free-text annotation from the lab on this specific result.nullwhen the lab did not attach one.status_reason— why afaultorundeliverableresult is unusable.nullfor every other status.variants— the specific genetic variants detected, each with SNV-level detail.
Clinical significance values
Genetic result statuses
Variant structure
Each genetic result contains avariants array. Each variant includes:
name— common name (e.g., APOE E4).clinical_significance— variant-level significance (may differ from the gene-level significance).conditions— associated diseases/conditions with descriptions.snvs— the underlying single nucleotide variants, each withrs_id,allele,reference_allele, and optional HGVS notation.
Documents
Thedocuments array in the results response contains references to downloadable lab report files. Each document has:
id— a file UUID. Pass this toGET /api/v1/documents/{id}to download the file.file_name— the file name, the same one the download sends (e.g.,20260405 - Quade Befund - 7642001234.pdf).original_file_name— the file name exactly as the lab or the uploader delivered it (e.g.,7642001234_B0012_FA_E.pdf).origin— who delivered the file:lab,member_uploadorstaff_upload.content_type— the media type of the file (e.g.,application/pdf). Most reports are PDFs. Uploaded scans can be images or CSV files.etag— the version of the file content; it changes whenever the bytes change. Store it and download again only when it changes. It is the standard HTTP entity tag, as used by S3 or Google Cloud Storage.size_bytes— the file size in bytes.lab_code— the lab code (tube barcode) the report belongs to;nullwhen the lab filed none.
Access to documents is validated against the profile that owns the document.
Emailing results to the customer
You can tell the customer by email that their results are ready. Call Email Results for an appointment, or Email Results for a home kit order. Each call sends one email. Calls are not deduplicated.- The email goes to the
emailof the profile. A placeholder@aniva.emailaddress is refused. - The email shows the name and the logo of the profile’s primary profile group.
- The email is in German when the profile
languageisde, and in English for all other languages. - Set
with_reportstotrueto attach the lab reports. - Add
noteto show a personal note in the email, at most 1000 characters.
409 with the reason
unsubscribed. To turn them on again, set transactional_emails_enabled to true with
Update Profile.
Results-ready emails
You can get an email when the results of a booking are ready. Setresults_ready_emails to up to 5
addresses on Create Appointment or
Create Home Kit Order. Change the list later with
Update Appointment or
Update Home Kit Order; [] turns the emails off.
- Each address gets one email, once every lab result of the booking is final.
- An address added after the results are final gets the email right away.
- The email links to the result page in the Aniva admin panel. The customer does not get it.
- Your key needs
results_viewaccess to the patient. Without it, the request returns403.