Data Export

When a practitioner submits a report, Tiro.health persists it to your data tenant and signals your system to fetch the result. This page covers how that callback works and how to retrieve the structured data.

Data export is the final step of a Capture API integration. It follows Data Import and the context launch: the user completes the form, clicks submit, and control returns to your application together with everything it needs to pull the report back.


Overview

The submission flow has three parts:

  1. User clicks submit. The practitioner completes their work in Tiro.health and submits.
  2. Data is persisted. The report is saved to your data tenant as a completed QuestionnaireResponse, and a human-readable narrative is generated.
  3. Redirect and retrieval. The user's browser is redirected to a URL you configured. That redirect is both the return path for the user and the trigger for your backend to fetch the data.

The Submit Callback

On submit, Tiro.health redirects the browser to your configured URL and appends the references of the resources that were just created as query parameters:

GET https://your-system.example.com/submit?response=QuestionnaireResponse/11427&task=Task/456
ParameterDescription
responseReference to the completed QuestionnaireResponse — the report.
taskReference to the Task that was fulfilled, when the report was launched from a task.

Extract the response reference from the query string, then call back into the FHIR API to retrieve the data. The redirect only tells you that a report is ready and which one — you still fetch the content yourself.


Configuring the Redirect

Set post_submit_redirect when you create the session with POST /session. The redirect is configured per session, so the return location can depend on where the launch came from.

A matching post_cancel_redirect controls where the user is sent if they cancel instead of submitting.


GET/QuestionnaireResponse

Fetch the QuestionnaireResponse

Once you have the response id from the redirect, fetch the QuestionnaireResponse. Use _include to pull the referenced Patient and Encounter into the same Bundle so you don't need extra round-trips.

The human-readable report is available directly on the response as the generated text narrative (XHTML), so most integrations that only need the report text can stop here.

Common parameters

  • _id — the QuestionnaireResponse id from the redirect.
  • _include=QuestionnaireResponse:subject — include the Patient.
  • _include=QuestionnaireResponse:encounter — include the Encounter.

Request

GET
/QuestionnaireResponse
curl -G https://reports.tiro.health/fhir/r5/QuestionnaireResponse \
  --data-urlencode "_id=11427" \
  --data-urlencode "_include=QuestionnaireResponse:subject" \
  --data-urlencode "_include=QuestionnaireResponse:encounter" \
  -H "Authorization: Basic {{apikey}}" \
  -H "Content-Type: application/fhir+json"

Response (searchset)

{
  "resourceType": "Bundle",
  "type": "searchset",
  "total": 1,
  "entry": [
    {
      "fullUrl": "https://reports.tiro.health/fhir/r5/QuestionnaireResponse/11427",
      "resource": {
        "resourceType": "QuestionnaireResponse",
        "id": "11427",
        "questionnaire": "http://templates.tiro.health/templates/unreadable-unique-id|1.0.1",
        "status": "completed",
        "subject": { "reference": "Patient/123" },
        "encounter": { "reference": "Encounter/456" },
        "text": {
          "status": "generated",
          "div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">...report narrative...</div>"
        }
      }
    }
  ]
}

GET/Composition/:id

Fetch the Composition

For a structured, document-style view of the report, request the Composition. Tiro.health builds it on the fly from the report's content: one section per block, each with a title, a generated narrative (text.div, XHTML), and a stable code.

The Composition shares the same id as the report — use the id from the response reference.

Why sections carry codes

Each section has a fixed code (LOINC or SNOMED CT) that is stable per template, unlike the linkIds inside a QuestionnaireResponse. This lets you map each section directly onto a field in your own system — for example, mapping section.code = 59776-5 ("Procedure findings") to your Findings field. Because the codes are fixed per template, your integration can rely on them.

Language

The Composition and its section narratives are generated in the language the clinician selected while completing the report. The other translations are dropped, so you always receive one consistent language version per report — never a mix.

Request

GET
/Composition/11427
curl -G https://reports.tiro.health/fhir/r5/Composition/11427 \
  -H "Authorization: Basic {{apikey}}" \
  -H "Content-Type: application/fhir+json"

Response

{
  "resourceType": "Composition",
  "id": "11427",
  "status": "preliminary",
  "type": {
    "coding": [{
      "system": "http://loinc.org",
      "code": "11506-3",
      "display": "Report"
    }],
    "text": "Report"
  },
  "date": "2025-11-20",
  "title": "CT scan report",
  "author": [{ "reference": "Practitioner/1" }],
  "subject": [{ "reference": "Patient/123" }],
  "section": [
    {
      "title": "Findings",
      "code": {
        "coding": [{
          "system": "http://loinc.org",
          "code": "59776-5",
          "display": "Procedure findings Narrative"
        }]
      },
      "text": {
        "status": "generated",
        "div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">...section narrative...</div>"
      }
    }
  ]
}

Retrieving the Composition through the Task

If your system tracked the Task from the import step, you can fetch the Task and its linked Composition in a single request using _include. This is convenient in integration engines (e.g. MIRTH) that key off your own Task identifier:

curl -G https://reports.tiro.health/fhir/r5/Task \
  --data-urlencode "identifier=http://hospital.example.com/tasks|TASK-54321" \
  --data-urlencode "_include=Task:output:composition" \
  -H "Authorization: Basic {{apikey}}" \
  -H "Content-Type: application/fhir+json"

The response is a Bundle containing the Task plus the Composition it references through its composition output.


Native Applications

For desktop and native integrations, the redirect can use a custom URI scheme instead of an HTTP URL to return the user to your application:

When the report runs inside an embedded browser, intercept the redirect navigation to capture the response reference programmatically rather than following it as a page load.

Was this page helpful?