<aside> ✨

What's New

Stay up-to-date with the latest features and improvements to our platform.

</aside>

2026


TruDiagnostic - v.1.54 (Aug. 11, 2026)

🔄 Changed Endpoints

GET /api/reports/{id} — now scoped to the owning practice

A report is now readable only by the practice that owns the kit the report was generated for. Requesting a report belonging to another practice returns 404 Not Found — the same response as a nonexistent report id, with no distinction made between the two.

This applies even when the same patient exists in more than one practice: sharing a patient does not grant one practice read access to another practice's reports or report PDFs.

{
  "error": {
    "message": "Error trying to locate resource"
  }
}

POST /api/orders/registrationsex accepts additional values

The per-item sex field previously accepted only "M", "F", "Male", or "Female". It now accepts the full set of biological sex values, case-insensitively:

Accepted input Interpreted as
M, Male Male
F, Female Female
Unknown Unknown
N/A, NA N/A
Other Other
Intersex Intersex

This is additive — existing "M" / "F" / "Male" / "Female" payloads are unaffected. These are the same values already reported on the biological_sex field of the registration object; the request side now accepts them too. Unrecognized values are still rejected, now with the message Sex is not a valid biological sex value.

FHIR ServiceRequest responses no longer include subject

POST /fhir/ServiceRequest and GET /fhir/ServiceRequest/{id} no longer return a subject element. The patient reference shown in the v.1.53 example was not reliably resolvable, so it has been removed rather than returned inconsistently. Correlate an order to your patient record using the identifier you supplied on create.

{
  "resourceType": "ServiceRequest",
  "id": "kit_a1b2c3d4e5f6...",
  "status": "draft",
  "intent": "order",
  "code": { "coding": [{ "system": "<http://loinc.org>", "code": "11502-2", "display": "Laboratory report" }] },
  "authoredOn": "2026-07-20T10:00:00Z"
}

⚡ Webhook Changes

FHIR-formatted webhook bodies for FHIR partner applications

Applications provisioned as FHIR partners — the same "umbrella" application type described in v.1.53 — now receive webhook payloads as FHIR R4 resources instead of the proprietary webhook_event envelope. Delivery, retries, headers, and subscription management are unchanged; only the request body differs. Standard applications continue to receive the existing envelope and require no action.

Event FHIR resource
kit.status.updated Task (code = lab-kit-processing)
order.status.updated Task (code = order-fulfillment)
report.generated, report.created DiagnosticReport

Task.status is a FHIR workflow status; the TruDiagnostic status string is preserved verbatim in businessStatus.

{
  "resourceType": "Task",
  "id": "kit_a1b2c3d4e5f6...",
  "identifier": [
    { "system": "<https://api.trudiagnostic.com/fhir/NamingSystem/kit-id>", "value": "BARCODEABC123" }
  ],
  "status": "in-progress",
  "businessStatus": {
    "coding": [
      { "system": "<https://api.trudiagnostic.com/fhir/CodeSystem/kit-status>", "code": "sample-received", "display": "Sample Received" }
    ]
  },
  "intent": "order",
  "code": {
    "coding": [
      { "system": "<https://api.trudiagnostic.com/fhir/CodeSystem/task-type>", "code": "lab-kit-processing", "display": "Lab kit processing" }
    ]
  },
  "focus": { "reference": "ServiceRequest/kit_a1b2c3d4e5f6..." },
  "for": { "reference": "Patient/usr_a1b2c3d4e5f6..." },
  "owner": { "reference": "Organization/trud-lab" }
}

order.status.updated additionally carries your externalId as a second identifier when one was supplied on the order.

For report.generated / report.created, the PDF is on presentedForm[].url as a /fhir/Binary/{id} link — fetch it with your normal Bearer token.

{
  "resourceType": "DiagnosticReport",
  "id": "rep_a1b2c3d4e5f6...",
  "status": "final",
  "code": {
    "coding": [{ "system": "<http://loinc.org>", "code": "11502-2", "display": "Laboratory report" }]
  },
  "performer": [{ "reference": "Organization/trud-lab" }],
  "presentedForm": [
    { "contentType": "application/pdf", "url": "<https://api.trudiagnostic.com/fhir/Binary/rep_a1b2c3d4e5f6>...", "title": "TruAge Complete" }
  ]
}

Only the event types above have a FHIR mapping. If a FHIR partner application subscribes to any other event, that delivery will not carry a FHIR resource body — subscribe only to the mapped events. Contact TruDiagnostic to have an application provisioned for FHIR webhook delivery.

⚠️ Breaking Changes

📋 Migration Notes


TruDiagnostic - v.1.53 (July 28, 2026)

🆕 New Endpoints

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"
        }
      ]
    }
  ]
}

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.

🔄 Changed Endpoints

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

{
  "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.

⚠️ Breaking Changes

📋 Migration Notes