Da Vinci DTR Implementation: Questionnaires, CQL Rules and the Part Everyone Under-Scopes
CTO & Co-Founder
CTO & Co-Founder at Nirmitee.io. Architects healthcare integrations across FHIR, SMART on FHIR, ABDM and NHCX, writing from production experience taking hospital software from sandbox to go-live.

DTR is described as the step where the payer's form gets filled in. That description is why it keeps getting under-scoped.
Documentation Templates and Rules is a rules engine. It executes logic you did not write, against clinical data you own, inside an authorisation session you have to establish, using artefacts that change without telling you. Of the three Da Vinci guides in the CMS-0057-F prior authorization chain (CRD, DTR and PAS), it is reliably the largest piece of work, and the gap between it and the other two is wider than most estimates allow for.
This is written for the consuming side: a provider-facing product implementing DTR, not a payer authoring the rules. If you are still deciding which side you are on, start with the CMS-0057-F scoping questions. The sections below cover the flow and the operations, the population rules, a worked example, how to test, and an open-source DTR server you can run.
The DTR flow in one picture
DTR sits between a CRD answer and a PAS request: it turns the payer's documentation rules into a questionnaire that is mostly answered before the clinician sees it.
- CRD answers an order with a coverage-information extension that says documentation is needed, carries a coverage-assertion id, and may offer a link that launches DTR.
- The DTR client (the EHR itself, or a SMART app it launches) asks the payer for the questionnaire package for that coverage and order, and gets back the Questionnaire, its CQL libraries and the value sets the logic needs.
- The client runs the CQL against the patient's record and prefills the QuestionnaireResponse.
- The clinician checks the prefilled answers, fills the gaps and signs.
- The response is saved in the EHR against the order. If prior authorization is needed, PAS carries it to the payer; if the payer only wants it with the claim, it travels as an attachment.
On the payer side the guide allows one door only: payers support a single endpoint for every DTR operation (§spec-6). A plan with several delegated review vendors still exposes one endpoint and routes behind it, the same rule CRD applies.
What happens inside a session
1. SMART launch
DTR typically runs as a SMART on FHIR app launched from within the EHR session, carrying its own authorisation context and its own scopes. If you are the EHR, you are the launcher, and you control this. If you are an app inside someone else's EHR, you inherit every quirk of their SMART implementation, and those quirks differ enough that a working DTR launch in one host tells you very little about the next.
2. Fetch the artefacts
The Questionnaire and its associated CQL library come from the payer. Both must be version-pinned at fetch time, because the response you produce has to be interpretable against the rules that generated it. A response validated against rule set v3 and adjudicated against v4 is a class of bug that is very hard to diagnose after the fact.
3. Gather the inputs
The CQL will reference clinical data by US Core profile. Your record does not store it that way. This step is a query against your own system, shaped to produce what the rules expect, and it is where the effort concentrates.
4. Execute the rules
CQL runs against the gathered data and decides three things: which items are shown, which are prefilled, and which are skipped entirely. You need a CQL execution environment for this. There are open-source engines available and they are usable, but "usable" is not "drop-in": expect to spend real time on the integration between the engine and your data access layer.
5. The clinician fills the gaps
Only the items the rules could not answer. The quality of steps 3 and 4 determines how many items that is, and the number is the entire user-facing value of DTR. A DTR implementation that prefills nothing is a web form with extra infrastructure.
6. Emit the QuestionnaireResponse
The version-stamped artefact that PAS carries to the payer. Straightforward once extraction works; a steady source of validation failures until it does.
The four operations a DTR payer server exposes
A DTR payer server has four operations, and only one of them does most of the work.
$questionnaire-packageis mandatory. The client sends the Coverage and the order (plus optional context); the payer returns everything needed to render and prefill the form without another call.$next-questionruns adaptive questionnaires: the client posts the answers so far and the payer returns the next item, or says the form is complete.$log-questionnaire-errorslets a client report a questionnaire that would not render or CQL that failed. It is the feedback loop that improves content in production, so treat its feed as a work queue.ValueSet/$expandis needed whenever the package refers to a value set by canonical URL instead of carrying it.
Inside the package, the Questionnaire links to its logic through Structured Data Capture extensions: cqf-library on the Questionnaire, and initialExpression or candidateExpression on each item that can be prefilled. The Library holds the CQL source and, ideally, the compiled ELM, so the client never needs a CQL translator at runtime. The guide pins the language: CQL 1.5 (§spec-92).
The extraction gap
This is the part to internalise. The CQL is written against US Core profiles. Your product is written against your product. Every DTR estimate lives or dies in the distance between those two things.
The mapping is bespoke to your data model, and the difficulty is rarely uniform across resources. Conditions and medications usually map reasonably. Labs bring code system gaps: the CQL wants LOINC, your results store may carry local codes with an incomplete crosswalk. Documents and attachments are frequently the worst, because the rules want a specific document type and your system has a blob store with human-entered titles.
How much of a payer rule can the chart answer? We classified every criterion in a sample of five publicly posted coverage policies (155 criteria in total, documents read on 15 September 2026). About 30% of them (47 of 155) could be answered from coded EHR data such as age, a diagnosis, a medication, a lab value or a score. The rest needed a clinician's attestation (22%), review of an attached document (19%), reading a note (14%) or clinical judgment (13%); 2% depended on the payer's own data. The share ran from 79% for a continuous glucose monitor policy down to 4% for an orthognathic surgery policy. The classification is our own and was not clinician-reviewed, and five policies is a small sample, so read it as a direction rather than a benchmark. The direction is clear enough: most of a DTR form is designed questions and evidence handling, and CQL prefill covers the minority.
Three consequences worth planning for:
- Missing data is not an error case; it is the normal case. Decide early whether a rule referencing an element you do not have fails loudly, fails open, or falls through to asking the clinician. All three are defensible; the wrong outcome is each part of the codebase choosing differently.
- The extraction layer is reusable and should be built as such. It is the same category of work as payer data normalisation, in the opposite direction, and the two should share a canonical model rather than each having their own.
- Coverage grows per payer. Each new payer's rule library references elements the previous ones did not. The curve flattens, but it does not flatten quickly.
Population rules: what prefilled is allowed to mean
A prefilled answer is only useful if the clinician can trust where it came from, and the guide is precise about that.
- The client runs the CQL and fills an answer wherever an expression returns a value (§spec-54), and marks automatically filled answers so they can be told apart from typed ones (§spec-55). The origin.source extension records whether an answer came from the chart, the user or an earlier response.
- When an expression returns nothing, the item stays empty for the clinician. The client does not guess.
- The clinician can change any prefilled answer (§spec-62), and the change is recorded as a manual entry.
- Where an answer came from a specific resource, the client should keep a reference to it so the payer can see the evidence (§spec-66).
- The client saves the QuestionnaireResponse in the EHR, in progress or complete, so work survives between sessions (§spec-78), and attaches the completed response to the order (§spec-87).
- Speed is specified too: roughly five seconds for the package fetch and first population, and one second for
$next-questionat the 90th percentile (§spec-38).
Two rules bind the payer. It cannot insist that providers use its own DTR app instead of the EHR's built-in client (§spec-1), and it accepts a QuestionnaireResponse completed by any conformant client (§spec-41, §spec-42, §spec-45). That second rule is the interoperability guarantee, and the reason one package has to work in every client.
Chart evidence and clinician answers carry different origins. Missing evidence stays unresolved until someone reviews it.
Standard versus adaptive questionnaires
A standard questionnaire arrives whole; an adaptive one arrives a question at a time. DTR clients have to handle both (§spec-16), while a payer may use either.
Standard forms are simple, work once fetched, and are what most payers publish first. Adaptive forms, driven by $next-question, let the payer stop as soon as a decision is reachable and keep its full decision tree private, at the cost of a round trip per question and a client that holds state. They are still rare, and they earn their place where a plan's criteria are proprietary or where most patients have a short path to approval.
Failure modes worth designing against
Two deserve particular attention, because neither raises an error.
Silent rule staleness
A cached rule set that has gone out of date does not raise an error. It runs perfectly and asks the wrong questions. Nobody notices until a payer starts rejecting submissions or, worse, accepting ones assembled against outdated requirements. Drift detection (a scheduled check of artefact versions against the payer, with an alert) is not a nice-to-have. It is the difference between a system you can trust and one you cannot.
Prefill that is subtly wrong
The most serious of the six, because it is worse than no prefill at all. If your extraction maps the wrong field, DTR presents a plausible answer, and a clinician signs off on an assertion your mapping invented. That is a clinical documentation problem wearing an integration costume. Every prefilled value should be traceable to its source element, and the ones derived through any transformation should be visually distinguished from the ones read directly.
Where the content comes from: policy to questionnaire to CQL
A DTR package is a build artefact, and on the payer side something has to produce it from written medical policy.
- A policy catalog of criteria and required documentation per code, line of business and product, each with a version, an effective date and an owner. It is the same catalog CRD's requirement matrix is compiled from.
- Questionnaire authoring, where each criterion becomes an item with a linkId, a type, answer options and the extensions that say how it can be prefilled.
- CQL authoring for every item the chart can answer, against US Core profiles and VSAC value sets.
- Compilation and testing: CQL to ELM, then a run against synthetic patients to prove each expression returns what its author meant.
- Versioned publication behind
$questionnaire-package, keyed to the same code and product CRD used, with old versions kept for requests already in flight.
The endpoints are engineering; the catalog and its questionnaires are what a plan maintains for years. If drug prior authorization moves onto the same rails, as CMS-0062-P proposes, the content grows with the formulary.
Three shapes a DTR client can take
- Native in the EHR. The EHR renders the questionnaire, runs the CQL with its own engine and stores the response. The payer's only job is to publish good packages.
- A SMART app launched from the CRD card. The app fetches the package, prefills from the EHR's FHIR API and writes the response back. The HL7 Foundry reference DTR app works this way, as do many provider-side vendors.
- A payer-hosted service behind the plan's own facade, which runs the CQL against data the plan holds plus what it fetches from the EHR with the launch token. It suits plans with delegated vendors: one questionnaire endpoint, one engine, vendors supplying content in a shared format.
A payer's packages have to work in all three, which in practice means CQL that depends only on the US Core profiles EHRs actually serve, value sets that expand, and questionnaires a generic SDC renderer can draw.
A worked example (synthetic): the lumbar MRI questionnaire
Here is one request end to end. The patient, the policy and the numbers are invented. The policy for a lumbar spine MRI without red-flag symptoms asks for six weeks of conservative therapy, documented neurological findings or a red flag, and no lumbar MRI in the past year. The payer's package holds one Questionnaire with nine items and one Library with three CQL definitions.
- Conservative therapy. The CQL looks for physical therapy or NSAID treatment with dates or a recorded outcome. It finds a physiotherapy referral from June and nothing after it. The referral is attached as evidence, but the item is flagged for the clinician to confirm: a referral does not show that six weeks of therapy happened, and a missing record does not show that it did not.
- Recent imaging. The CQL searches for a lumbar MRI in the past 365 days, finds none, and fills the item as "none found in this record", with the query kept as its source so the clinician can correct it if the scan was done elsewhere.
- Neurological findings. The CQL finds a radiculopathy diagnosis recorded at the visit and fills the item with a reference to that Condition.
Five of the nine items arrive prefilled with their sources, one is flagged for confirmation, and three are left blank: pain severity, red-flag symptoms and a short clinical summary. The clinician confirms the therapy dates, answers the rest and signs; the response goes onto the order and PAS carries it. The payer still decides. Using the same policy identifier in CRD, DTR and adjudication lets a plan auto-approve where its rules allow, but nothing in DTR guarantees an approval.
The same package, unchanged, has to work when Epic renders it natively, when a SMART app renders it, and when a payer-hosted service fills it. That is why its CQL uses only US Core profiles and VSAC value sets.
How to sequence the build
Start with the CQL spike. Take one real payer's rule library, run it against your own data, and count how many elements it asks for that you cannot supply. Two weeks. This single exercise will move your estimate further than anything else you can do, and it is frequently the finding that changes the shape of the project, sometimes into "we should phase DTR into next year and ship CRD plus PAS first."
Then the extraction layer, because the spike told you exactly what it needs to cover. Longest phase, and the most reusable output.
Then the renderer. Build it against the full Questionnaire item surface, not the subset your first payer happens to use. The temptation to build only what payer one requires is strong and the rework is guaranteed.
Then versioning and operations. Rule refresh, drift detection, per-payer pinning and an alert path when a template changes. This is the phase that gets cut under pressure and the one that determines whether the system still works in eighteen months.
How to test DTR before you meet a real EHR
DTR can be tested end to end without a provider partner, in five steps from a local reference stack to your own CQL harness.
- The HL7 Foundry Burden Reduction bundle runs the reference payer server with sample questionnaires, the reference DTR app and the CDS-Library of CQL. It needs a VSAC key.
- The Inferno DTR test kit exercises
$questionnaire-package,$next-questionand error logging in its payer server suites for 2.0.1 and 2.2.0, and self-hosts like the CRD kit. - The Acentra Health sandbox currently exposes
$questionnaire-packageon synthetic data, which is enough to prove your fetch and prefill path but not the adaptive one. - Epic on FHIR's "CMS Prior Auth" template apps list the scopes a SMART DTR client needs in Epic's sandbox; a registered client is the prerequisite, and production use needs Epic's review.
- Your own CQL harness, running each library against a synthetic cohort with expected answers. No kit gives you this test, and it is the one that catches an expression that compiles but returns null on every real patient.
An open-source DTR server, tested with Inferno
Nirmitee publishes the open-source Da Vinci DTR payer server (Inferno results in the README) under the Apache 2.0 licence. It is written in Go and in .NET 10 with identical behaviour and serves DTR 2.2.0 and STU 2.0.1 side by side. On the public inferno.healthit.gov instance it passes the DTR payer server suites apart from two Inferno test-kit issues, each of which fails any conformant server.
| Inferno suite | Test kit | Passed | Failed | Why the failures happen |
|---|---|---|---|---|
| DTR Payer Server v2.2.0 | Da Vinci DTR Test Kit v0.18.0 | 43 | 2 | Kit issue #130 (open): the kit's must-support list requires an extension the DTR 2.2.0 profiles forbid |
| DTR Payer Server v2.0.1 | Da Vinci DTR Test Kit v0.18.0 | 17 | 2 | Kit issue #131: an earlier test clears the data two later tests validate. Fixed upstream on 22 September 2026, not yet deployed to inferno.healthit.gov |
The runs date from 12 September 2026 (one further v2.2.0 test was omitted because the sample responses contain no Binary resources). The README links every public session and lists each failing test against its upstream issue. Inferno results are conformance evidence; CMS runs no certification program. The questionnaires in the repository are synthetic.
This is the shape of a $questionnaire-package response from the server, trimmed so each resource shows only its identity. The Questionnaire always comes first, followed by exactly one QuestionnaireResponse to start from, then the Library with CQL and ELM, then the value sets. An outcome OperationOutcome is added only when something needs reporting.
{
"resourceType": "Parameters",
"meta": {
"profile": [
"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/dtr-qpackage-output-parameters|2.2.0"
]
},
"parameter": [
{
"name": "packagebundle",
"resource": {
"resourceType": "Bundle",
"meta": {
"profile": [
"http://hl7.org/fhir/us/davinci-dtr/StructureDefinition/DTR-QPackageBundle|2.2.0"
]
},
"type": "collection",
"timestamp": "2026-09-12T06:17:14Z",
"entry": [
{
"fullUrl": "https://payer.example.org/fhir/Questionnaire/hospital-bed",
"resource": {
"resourceType": "Questionnaire",
"id": "hospital-bed",
"url": "https://nirmitee.io/fhir/Questionnaire/hospital-bed",
"version": "1",
"status": "active"
}
},
{
"fullUrl": "urn:uuid:82ded622-12f7-56ce-8256-3c1297f98322",
"resource": {
"resourceType": "QuestionnaireResponse",
"status": "in-progress",
"questionnaire": "https://nirmitee.io/fhir/Questionnaire/hospital-bed|1"
}
},
{
"fullUrl": "https://payer.example.org/fhir/Library/HospitalBedPrepopulation",
"resource": {
"resourceType": "Library",
"id": "HospitalBedPrepopulation",
"status": "active",
"content": [
{
"contentType": "text/cql"
},
{
"contentType": "application/elm+json"
}
]
}
},
{
"fullUrl": "https://payer.example.org/fhir/ValueSet/hospital-bed-diagnoses",
"resource": {
"resourceType": "ValueSet",
"id": "hospital-bed-diagnoses",
"status": "active"
}
}
]
}
}
]
}Which version to build to. CMS-0057-F recommends the Da Vinci guides rather than requiring a version, but the EHR side has already moved. The FY 2027 IPPS/LTCH final rule (published 4 August 2026, effective 1 October 2026) replaced the versions ONC certifies EHR modules against with CRD 2.2.1, DTR 2.2.0 and PAS 2.2.1, with no transition period. From October, an EHR certified for DTR speaks DTR 2.2.0, so a payer endpoint that serves only 2.0.1 will meet newer clients it cannot fully answer. The proposed CMS-0062-P would require payers to use the 2.2 guides as well. Serving both versions side by side, as the server above does, is the practical answer while clients upgrade.
The build-versus-buy question, specifically for DTR
DTR is the component where the buy case is strongest, because the CQL engine and the questionnaire renderer are genuinely general-purpose and someone else has already absorbed the edge cases.
The part that is never general-purpose is the extraction layer. It maps a payer's expectations onto your data model, and nobody else has your data model. Whatever you buy, you will build that, so evaluate vendors on how cleanly they let you plug your own extraction in, rather than on whether they claim Da Vinci support. Everyone claims Da Vinci support.
Where Nirmitee.io fits
Healthcare-only, FHIR R4 native, with production EHR integrations delivered for healthtech companies and an open-source Headless EHR covering 28 clinical domains and 70+ FHIR R4 resources, which means the US Core surface the CQL expects is territory we work in daily.
The two-week CQL spike is the engagement we would recommend before anyone commits a quarter to DTR, including teams that end up doing the rest themselves. If you want a second read on what your extraction gap looks like, a 15-minute technical conversation is usually enough to size it.
For payer-side questionnaire and CQL pipelines and the full CRD, DTR and PAS stack, see our CMS-0057-F implementation services; for the wider integration work, our healthcare interoperability solutions. Talk to our team.
Explore the CMS-0057-F series
- CMS-0057-F Explained: Requirements and 2027 API Deadlines
- Da Vinci CRD Explained: Coverage Requirements Discovery
- Da Vinci DTR Implementation: Questionnaires, CQL and Prior Authorization (this article)
- Da Vinci PAS Explained: FHIR Prior Authorization and X12 278
- CMS-0057-F Payer Architecture for Delegated Vendors
- CMS-0057-F API Testing: Inferno, Sandboxes and Evidence
Sources
- HL7: Da Vinci Documentation Templates and Rules (DTR) Implementation Guide
- HL7: Clinical Quality Language (CQL) specification
- HL7: FHIR R4 Questionnaire resource
- HL7: SMART App Launch Framework
- HL7: DTR $questionnaire-package operation
- HL7: Structured Data Capture
- FY 2027 IPPS/LTCH final rule, Federal Register 2026-15833 (ONC standards update, effective 1 October 2026)
- Inferno Da Vinci DTR test kit (GitHub)
- HL7 Foundry
- Nirmitee davinci-dtr-server (GitHub)
Ready to scale?
Talk to our healthcare engineering team about building, integrating, and shipping faster.
Frequently Asked Questions
What does Da Vinci DTR actually do?
Why is DTR the largest part of a Da Vinci implementation?
How should a DTR build be sequenced?
What is the most dangerous DTR failure mode?
Does CMS require DTR?
Can a payer require providers to use its own DTR app?
Is there an open-source DTR server tested with Inferno?


