Skip to content
v1.0.2

For a more practical, narrative guide to managing jobs after kick-off (listing, pausing, cancelling, changing priority, deleting) than the technical reference above, see the Task API page.

$evaluate-cohort — Cohort Preview ​

Unlike $extract-data, $evaluate-cohort does not follow the async Bulk Data pattern below: it evaluates the cohort synchronously and returns the matching cohort directly in the response body as a FHIR List resource, without creating a job or persisting anything under output/. Use it to preview a cohort (e.g. check its size or membership) before committing to a full extraction.

The request body is either a full CRTDL (only its cohortDefinition field is used) or a bare CCDL (structured query) — passed as plain JSON directly, not Base64 encoded or wrapped in a Parameters resource.

sh
curl -s 'http://localhost:8080/fhir/$evaluate-cohort' -H "Content-Type: application/json" -d @src/test/resources/CRTDL/CRTDL_observation.json -v

Implementation Details ​

The TORCH REST API follows the Asynchronous Bulk Data Request Pattern described below for $extract-data.

$extract-data Kick-off ​

The $extract-data endpoint initiates the extraction. It expects a FHIR Parameters resource containing a Base64 encoded CRTDL definition. resource with a crtdl parameter containing a valueBase64Binary CRTDL. In all examples torch is configured with the base url http://localhost:8080.

sh
scripts/create-parameters.sh src/test/resources/CRTDL/CRTDL_observation.json | curl -s 'http://localhost:8080/fhir/$extract-data' -H "Content-Type: application/fhir+json" -d @- -v

Request Body Structure ​

The Parameters resource created by create-parameters.sh look like this:

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "crtdl",
      "valueBase64Binary": "<Base64 encoded CRTDL>"
    }
  ]
}

Optionally patient ids can be submitted for a known cohort, bypassing the cohort selection in the CRTDL:

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "crtdl",
      "valueBase64Binary": "<Base64 encoded CRTDL>"
    },
    {
      "name": "patient",
      "valueString": "<Patient Id 1>"
    },
    {
      "name": "patient",
      "valueString": "<Patient Id 2>"
    }
  ]
}

Optionally, consent diagnostics (raw provisions, final consent periods, and per-resource consent decisions) can be opted into via consentDiagnostics; see Consent Diagnostics:

{
  "resourceType": "Parameters",
  "parameter": [
    {
      "name": "crtdl",
      "valueBase64Binary": "<Base64 encoded CRTDL>"
    },
    {
      "name": "consentDiagnostics",
      "valueBoolean": true
    }
  ]
}

Result Files ​

Upon successful completion, the data extraction results consist of multiple NDJSON files:

  • One NDJSON file per patient batch, each containing FHIR transaction Bundles
  • One core.ndjson file, containing a single FHIR transaction Bundle with all non-patient-specific resources

Patient Batch Files ​

Each patient batch NDJSON file contains:

  • One transaction Bundle per patient
  • Each Bundle includes:
    • exactly one Patient resource
    • all patient-specific resources extracted according to the CRTDL (e.g. Encounter, Condition, Observation, etc.)

Patient batch files can be processed independently and in any order.

Core Bundle File ​

The core.ndjson file contains:

  • a single transaction Bundle
  • all non-patient-specific resources (e.g. shared reference data such as Medication)

For referential integrity, core.ndjson must be processed before any patient batch files.
For this reason, the provided transfer script uploads core.ndjson first.

If core.ndjson contains resources but no patient batch files are present, this indicates that:

No patient survived the extraction, but core (non-patient) resources were still loaded.

Per batch, TORCH may additionally write a <batchId>_consent.ndjson file holding the minimized Consent/Encounter resources used to compute patient consent decisions, for independent audit. These files are linked from the Task API, not from this endpoint's output array. See that page for details on when they're written and what they contain.


Job Completion Manifest Extensions ​

When a job completes, the GET /fhir/__status/{jobId} response follows the FHIR Async Bulk Data manifest format. The output array contains only FHIR NDJSON Bundle files — one file per patient batch (each containing one Bundle per patient) and one core.ndjson. Non-resource data (diagnostics, issues) is never placed in output, because downstream consumers process every entry there as a FHIR resource file.

TORCH-specific data is surfaced in the extension array. Five extension URLs are defined:

urlContentPresent when
https://torch.mii.de/fhir/StructureDefinition/torch-jobFull serialised job state (batches, timings, version)Always
torch-job-diagnostics-summaryCohort total, final patient total and per-stage processing durations; see Job DiagnosticsDiagnostics were collected (i.e. at least one batch completed)
torch-resource-exclusionsvalueUrl pointing to a CSV file containing resource exclusion events; see Job DiagnosticsSame as above
torch-patient-exclusionsvalueUrl pointing to a CSV file containing patient exclusion events; see Job DiagnosticsSame as above
torch-raw-provisionsvalueUrl pointing to a CSV file containing the raw consent provisions; see Consent DiagnosticsconsentDiagnostics was requested and same as above
torch-final-periodsvalueUrl pointing to a CSV file containing the final consent periods; see Consent DiagnosticsconsentDiagnostics was requested and same as above
torch-consent-considered-resourcesvalueUrl pointing to a CSV file containing per-resource consent decisions; see Consent DiagnosticsconsentDiagnostics was requested and same as above
torch-job-issuesList of {severity, msg, diagnostics} objects recording warnings and errors that occurred during processing (e.g. skipped batches, retries)At least one issue was recorded

Example completed manifest:

json
{
  "transactionTime": "2026-01-15T10:30:00Z",
  "request": "http://localhost:8080/fhir/__status/<jobId>",
  "requiresAccessToken": false,
  "output": [
    {
      "type": "NDJSON Bundle",
      "url": "http://fileserver/<jobId>/<batchId>.ndjson"
    },
    {
      "type": "NDJSON Bundle",
      "url": "http://fileserver/<jobId>/core.ndjson"
    }
  ],
  "extension": [
    {
      "url": "https://torch.mii.de/fhir/StructureDefinition/torch-job",
      "valueObject": {
        "id": "<jobId>",
        "status": "COMPLETED",
        ...
      }
    },
    {
      "url": "torch-job-diagnostics-summary",
      "valueUrl": "http://fileserver/<jobId>/reports/job-summary.json",
      "valueObject": {
        "Num-Cohort-Patients": 3,
        "Num-Final-Patients": 0,
        "Duration-Measurements": {
          "COPY_REDACT": {
            "medianNanos": 34400,
            "averageNanos": 26300
          },
          "DIRECT_LOAD": {
            "medianNanos": 17928800,
            "averageNanos": 9044250
          },
          "REFERENCE_RESOLVE": {
            "medianNanos": 177800,
            "averageNanos": 155050
          },
          "CONSENT_FETCH": {
            "medianNanos": 56800,
            "averageNanos": 56800
          },
          "CASCADING_DELETE": {
            "medianNanos": 30600,
            "averageNanos": 25700
          }
        },
        "Patient-Exclusions": {
          "CASCADING_DELETE": 0,
          "DIRECT_LOAD": 3,
          "CONSENT": 0
        },
        "Resource-Exclusions": {
          "med-adm-group": {
            "Must-Have": {
              "MedicationAdministration.category": 2
            },
            "Consent": 0,
            "Reference-Not-Found": 0,
            "Resource-Outside-Batch": 0,
            "Cascading-Delete": 0
          }
        },
        "Resource-Inclusions": {
          "med-adm-group": 12
        }
      }
    },
    {
      "url": "torch-resource-exclusions",
      "valueUrl": "http://fileserver/<jobId>/reports/resource-exclusions.csv"
    },
    {
      "url": "torch-patient-exclusions",
      "valueUrl": "http://fileserver/<jobId>/reports/patient-exclusions.csv"
    },
    {
      "url": "torch-raw-provisions",
      "valueUrl": "http://fileserver/<jobId>/reports/raw-provisions.csv"
    },
    {
      "url": "torch-final-periods",
      "valueUrl": "http://fileserver/<jobId>/reports/final-periods.csv"
    },
    {
      "url": "torch-consent-considered-resources",
      "valueUrl": "http://fileserver/<jobId>/reports/consent-considered-resources.csv"
    },
    {
      "url": "torch-job-issues",
      "valueObject": [
        {
          "severity": "WARNING",
          "msg": "Batch <id> skipped: no consenting patients",
          "diagnostics": ""
        }
      ]
    }
  ]
}

Example ​

Given:

  • Bundle size: 20
  • 100 patients
  • Per patient:
    • 1 Encounter
    • 1 Diagnosis
  • Shared references:
    • 30 Medication resources

The extraction result will contain:

  • 5 patient batch NDJSON files (each containing 20 transaction Bundles)
  • 1 core.ndjson file

Each patient batch file contains:

  • one transaction Bundle per patient
  • each Bundle includes:
    • 1 Patient
    • ≥1 Diagnosis
    • ≥1 Encounter

The core.ndjson contains:

  • a single transaction Bundle
  • 30 Medication resources