<aside> ✨
What's New
Stay up-to-date with the latest features and improvements to our platform.
</aside>
FHIR R4 API
A new FHIR-conformant surface is available alongside the existing REST API, for integrators (e.g. EHR systems) that prefer to exchange orders and results as FHIR resources. It authenticates with the same Bearer token as the rest of the Public API.
| Endpoint | Description |
|---|---|
GET /fhir/metadata |
CapabilityStatement describing supported resources and interactions. No authentication required. |
POST /fhir/ServiceRequest |
Places an order from a FHIR ServiceRequest with a contained Patient. Returns the created ServiceRequest (id = kit Uid). |
GET /fhir/ServiceRequest/{id} |
Reads a ServiceRequest by kit Uid (kit_...). status reflects kit progression. |
GET /fhir/DiagnosticReport/{id} |
Reads a DiagnosticReport by report result Uid (rep_...). The PDF is on presentedForm. |
GET /fhir/DocumentReference/{id} |
Reads a DocumentReference by report result Uid (rep_...). Contains a presigned PDF URL. |
GET /fhir/Binary/{id} |
Redirects (302) to a presigned S3 URL for the report PDF, by report result Uid. |
All FHIR responses are served as application/fhir+json. The create endpoint accepts either application/fhir+json or application/json. Errors are returned as a FHIR OperationOutcome rather than the standard REST API's error shape.
POST /fhir/ServiceRequest request:
{
"resourceType": "ServiceRequest",
"identifier": [{ "value": "your-external-id" }],
"code": {
"coding": [{ "code": "sku_a1b2c3d4e5f6..." }]
},
"requester": {
"identifier": { "value": "pra_a1b2c3d4e5f6..." }
},
"contained": [
{
"resourceType": "Patient",
"name": [{ "given": ["John"], "family": "Doe" }],
"birthDate": "1990-05-20",
"telecom": [{ "system": "phone", "value": "+15555551234" }],
"address": [
{
"line": ["123 Main St"],
"city": "Lexington",
"state": "KY",
"postalCode": "40503",
"country": "USA"
}
]
}
]
}
code.coding[].code — the TruDiagnostic SKU Uid (sku_...) being ordered.requester.identifier.value — your practice Uid. Optional for a standard application (defaults to your own practice; if supplied, must match it). Required if your application is an "umbrella" application entitled to place orders on behalf of multiple practices — see below.contained must include exactly one Patient with name, birthDate, telecom (phone), and a complete address (line, city, state, postalCode).Response (201 Created):
{
"resourceType": "ServiceRequest",
"id": "kit_a1b2c3d4e5f6...",
"status": "draft",
"intent": "order",
"code": { "coding": [{ "system": "<http://loinc.org>", "code": "11502-2", "display": "Laboratory report" }] },
"subject": { "reference": "Patient/usr_a1b2c3d4e5f6..." },
"authoredOn": "2026-07-20T10:00:00Z"
}
status reflects kit progression:
| Kit status | FHIR status |
|---|---|
| Not yet registered | draft |
| Disposed / marked for disposal / replacement requested | revoked |
| Result ready | completed |
| Anything else | active |
Umbrella applications: some partner integrations are provisioned as an "umbrella" application entitled to place orders for a set of child practices. If your application is provisioned this way, requester.identifier.value is required on every POST /fhir/ServiceRequest and must reference one of your entitled practices — the request is rejected otherwise. This has no effect on standard (non-umbrella) applications.
material_unit renamed to unactivated_kit
The GET /api/materialunits and GET /api/materialunits/{id} endpoints, and the material_unit object they return, have been renamed:
| Before | After |
|---|---|
GET /api/materialunits |
GET /api/unactivatedkits |
GET /api/materialunits/{id} |
GET /api/unactivatedkits/{id} |
object: "material_unit" |
object: "unactivated_kit" |
The object shape is otherwise the same (barcode, order, sku, status, createdAt, activatedAt), except barcode and sku are now nullable.
The object's id prefix also changed from mat_ to ukt_ — every unactivated_kit.id now starts with ukt_.
{
"object": "unactivated_kit",
"id": "ukt_a1b2c3d4e5f6...",
"barcode": "BARCODEABC123",
"order": "ord_a1b2c3d4e5f6...",
"sku": "sku_a1b2c3d4e5f6...",
"status": "available",
"createdAt": "2024-08-14T10:00:00Z",
"activatedAt": null
}
order object now includes unactivatedKits
The order object gains a new unactivatedKits array field — the collection kits shipped on the order that have not yet had a service activated against them. Each becomes a kit once activated via POST /api/orders/activate. Additive; existing integrations are unaffected.
POST /api/orders/activate — request field changes
MaterialUnitBarcode is renamed to UnactivatedKitBarcode.ProductId now accepts a SKU Uid (sku_...) or SKU code, the same identifier style used elsewhere in the API. A bare numeric product ID is no longer accepted.{
"Items": [
{
"ProductId": "sku_a1b2c3d4e5f6...",
"UnactivatedKitBarcode": "BARCODEABC123"
}
]
}
Every response now carries an X-Trace-Id header
All Public API responses now include an X-Trace-Id header for correlating a request with TruDiagnostic support/logs. It replaces the previous X-Request-ID header.
/api/materialunits → /api/unactivatedkits, and object: "material_unit" → object: "unactivated_kit". Update any hardcoded endpoint URLs or object type checks.POST /api/orders/activate: MaterialUnitBarcode → UnactivatedKitBarcode in the request body. ProductId must now be a SKU Uid or SKU code — integrations passing a numeric product ID must switch to one of those.unactivated_kit id prefix changed from mat_ to ukt_. If your integration matches on the mat_ prefix, update it to ukt_.X-Request-ID header removed. If your integration read X-Request-ID from responses (or sent one to control correlation), switch to reading X-Trace-Id. The new header is always server-generated; a client-supplied value is no longer echoed back.GET /api/materialunits[/…] to call GET /api/unactivatedkits[/…] instead, and update any object === "material_unit" checks to "unactivated_kit".POST /api/orders/activate request bodies: rename MaterialUnitBarcode → UnactivatedKitBarcode, and pass ProductId as a SKU Uid or SKU code instead of a numeric id.id prefix on unactivated_kit objects, update it from mat_ to ukt_.X-Trace-Id response header.No external API changes in this release. This version includes internal engineering improvements only.
POST /api/submissions or GET /api/submissions/{id} request/response behavior.POST /api/orders, GET /api/orders, POST /api/orders/{id}/cancel, POST /api/orders/activate, POST /api/registrations, or GET /api/registrations/{id}.Status property of OperationStartedResult/OperationCompletedResult<T>. No change to the serialized response shape for async operation endpoints.New sample.reprocessed webhook event
A new webhook event is available for subscribing to lab sample reprocessing. This event fires when a sample is sent back for reprocessing by the lab.
Subscribe using the event type: sample.reprocessed
{
"Object": "webhook_event",
"Type": "sample.reprocessed",
"Data": {
"SampleId": "1234",
"Kit": {
"Sku": "TruAge",
"KitId": "CAQL5G9WUL4AG7AL",
"KitIdExternal": ""
},
"ByUserId": 10042,
"BusinessUnitId": 1,
"PracticeId": 10042,
"PublicName": "sample.reprocessed",
"Version": 1,
"EventTime": "2026-06-30T14:00:00.0000000Z",
"IdempotentKey": "a1b2c3d4e5f6...",
"EventName": "SampleReprocessedInLabIntegrationEvent",
"Avatar": 2,
"AvatarName": "Provider",
"UniversalId": "usr_a1b2c3d4e5f6..."
},
"Id": "hook_a1b2c3d4e5f6..."
}
Key payload fields:
SampleId — identifier of the sample being reprocessedKit — kit context including barcode (KitId) and product SKUPracticeId — the practice associated with the kitPOST /api/reports — OpenAPI contract correction
In v.1.50, the OpenAPI spec for this endpoint incorrectly listed request body properties in snake_case (kit_id, report_type, render_strategy, render_details). The documented contract has been restored to camelCase (KitId, ReportType, RenderStrategy, RenderDetails).
Runtime behavior was never affected — the API accepts camelCase, PascalCase, and snake_case inputs regardless of what the spec shows. If your integration sends requests directly (not via a generated client), no changes are needed. If you regenerated a client from the Swagger spec between v.1.50 and this release, regenerate again to pick up the corrected property names.
Kit objects now include date_received_in_lab
The KitObject response shape now includes a date_received_in_lab field indicating the date the lab received the kit. This field is nullable and will be null for kits that have not yet been received.
Affected endpoints:
GET /api/kits/{id}GET /api/kitsGET /api/kits/searchGET /api/orders/search (responses include kit objects)Example response (new field):
{
"object": "kit",
"id": "kit_a1b2c3d4e5f6",
"status": "SampleReceived",
"date_created": "2024-08-13",
"date_received_in_lab": "2024-08-15"
}
Search query language: received_in_lab filter now supported
GET /api/kits/search now accepts received_in_lab as a filter field in the query parameter.
GET /api/kits/search?query=received_in_lab>2024-08-01
GET /api/kits/search?query=received_in_lab>=2024-08-01 AND received_in_lab<2024-09-01
Both changes are non-breaking and additive. Existing integrations continue to work without modification.
No external API changes in this release. This version includes internal engineering improvements only.
POST /api/orders, POST /api/orders/activate, and DELETE /api/orders/{id} are unchanged.POST /api/registrations or POST /api/orders/registration request/response contracts.List Samples for a Kit
Endpoint: GET /api/kits/{id}/samples
Returns all samples associated with a kit. Scoped to your application's practice.
Response 200:
{
"object": "list",
"data": [
{
"id": "smp_1a2b3c4d5e6f...",
"object": "sample",
"status": "Completed",
"arrayType": "EPICv2Custom",
"beadchipId": "207134830027_R01C01",
"kit": "kit_a1b2c3d4e5f6...",
"createdAt": "2026-02-10T14:23:00Z"
}
],
"hasMore": false
}
Get Sample