An open-source, payer-side implementation of the HL7 Da Vinci Coverage Requirements Discovery (CRD) Implementation Guide, written twice with identical behavior: once in Go and once in .NET 10. Both implementations pass the Inferno Da Vinci CRD Server test suites for CRD 2.2.1 and CRD STU 2.0.1 with zero failures.
The CMS Interoperability and Prior Authorization Final Rule (CMS-0057-F) requires impacted payers to offer a Prior Authorization API, with most API requirements starting in January 2027, and CMS recommends the Da Vinci Burden Reduction implementation guides for it: CRD, DTR (Documentation Templates and Rules) and PAS (Prior Authorization Support).
CRD is the first step in that flow. While a clinician books an appointment or signs an order, the EHR calls the payer's CDS Hooks service, and the payer answers in real time: is this covered, is prior authorization needed, what documentation is required, and where to go next. This repository is that payer service. It is meant as a working reference that payers, EHR vendors and integrators can read, run, test against and build on.
Tested with the Inferno Da Vinci CRD Test Kit v0.14.2, JWT algorithm ES384, on 12 September 2026. Report summaries are in docs/results/.
| Implementation | Suite | Run | Pass | Fail | Skip (optional) | Report |
|---|---|---|---|---|---|---|
| Go | CRD v2.2.1 | local, HTTP | 135 | 0 * | 7 | summary |
| .NET | CRD v2.2.1 | local, HTTP | 135 | 0 * | 7 | summary |
| Go | CRD v2.0.1 | local, HTTP | 85 | 0 * | 6 | summary |
| .NET | CRD v2.0.1 | local, HTTP | 85 | 0 * | 6 | summary |
| Go | CRD v2.2.1 | public inferno.healthit.gov, HTTPS | 136 | 0 | 7 | summary, session |
| Go | CRD v2.0.1 | public inferno.healthit.gov, HTTPS | 86 | 0 | 6 | summary, session |
| .NET | CRD v2.2.1 | public inferno.healthit.gov, HTTPS | 136 | 0 | 7 | summary, session |
| .NET | CRD v2.0.1 | public inferno.healthit.gov, HTTPS | 86 | 0 | 6 | summary, session |
* Local runs use plain HTTP, so test 1.01 (TLS 1.2 or higher) cannot pass there. The raw local reports list it as the only failure and it is excluded from the count. On the public Inferno instance the servers sit behind an HTTPS tunnel and test 1.01 passes, which is why the public pass counts are one higher.
Captured on inferno.healthit.gov (CRD test kit v0.14.2) from the sessions linked in the table above.
CRD v2.2.1: whole suite passed (Go left, .NET right)
| Go | .NET |
|---|---|
![]() |
![]() |
CRD v2.2.1: Discovery group, including test 1.01 TLS 1.2 or higher
| Go | .NET |
|---|---|
![]() |
![]() |
CRD v2.2.1: Specific Coverage Responses (technical issues, no member, coverage not found, no active coverage)
| Go | .NET |
|---|---|
![]() |
![]() |
CRD v2.0.1: whole suite and Discovery with TLS passed
| Go | .NET |
|---|---|
![]() |
![]() |
![]() |
![]() |
The hook groups under "3 Hooks" are marked Optional by the test kit (a server chooses which hooks it supports), so Inferno shows them with a lighter check; every one of them passed.
The optional skips are validations for card types the sample payer rules do not return on the secondary hooks (Launch SMART Application, Request Form Completion and Propose Alternate Request cards on encounter-start, order-select and encounter-discharge). Passing Inferno is a conformance signal, not a certification.
- Six CDS Hooks services for each CRD version:
appointment-book,encounter-start,encounter-discharge,order-select,order-signandorder-dispatch. CRD 2.2.1 is served under/v221/cds-servicesand STU 2.0.1 under/v201/cds-services, side by side in one process. - Discovery with prefetch templates for every service, plus the 2.2.1
davinci-crd.versionanddavinci-crd.configuration-optionsextensions. - All CRD response types: Coverage Information system action (
ext-coverage-information), Instructions, External Reference, Launch SMART Application, Request Form Completion (Task plus Questionnaire), Propose Alternate Request, Additional Orders and Create or Update Coverage Information. - Coverage information on the primary hooks (appointment-book, order-sign, order-dispatch) for every focus resource: covered status, prior authorization need, documentation need and purpose, coverage assertion ids and satisfied-PA ids. Secondary hooks never ask for clinical or administrative information.
- Specific coverage outcomes tested by v2.2.1 group 4: technical issues (EHR FHIR server errors), no member found, coverage not found and no active coverage.
- Data acquisition: prefetch first, then parallel reads from the EHR
fhirServerusingfhirAuthorization, with a per-fetch timeout and classified failures. Echoed resources keep their original JSON key order. - Client authentication per CDS Hooks "Trusting CDS Clients": bearer JWTs signed with ES384 or RS384 (ES256
and RS256 are also accepted), an issuer allowlist, keys from the issuer JWKS (
jkuonly under a trusted issuer),audchecked against the service URL including tunnels and proxies,expandiatwith clock skew, and ajtireplay cache. Failures return 401. - Configuration options:
coverage-infoand per-topic options (limits,guideline,appropriate-use,therapy-alternatives-opt,clinical-reminder,insurance); unknown options, context fields and top-level fields are ignored. - Request validation: 400
invalid_requestorinvalid_contextfor malformed calls, 422unprocessable_contextfor unusable context. - Rules as data: payer decisions, the synthetic member and card templates live in spec/payer-rules.json (16 sample rules), shared by both implementations.
- Audit log: one JSON line per hook call (request, response, fetches, JWT
iss/kid/jti, outcome, matched rules) in a daily file, with access tokens redacted. - Library plus host: no global state and a configurable route prefix, so the CRD module can be mounted next to DTR and PAS in one process later. Docker images run as a non-root user.
Each implementation is a CRD library, a shared package for cross-cutting concerns and a thin host.
flowchart LR
EHR["EHR as CDS client<br/>(Inferno during testing)"]
RULES[("spec/payer-rules.json")]
FHIR[("EHR FHIR server")]
JWKS[("Client JWKS")]
subgraph proc["CRD server process"]
direction TB
HOST["Host<br/>Go: cmd/crd-server<br/>.NET: Nirmitee.DaVinci.Crd.Host"]
subgraph lib["CRD library (Go: crd, .NET: Nirmitee.DaVinci.Crd)"]
DISC["Discovery"]
VAL["Request validation"]
ENG["Engine: focus resources,<br/>data, determination"]
RESP["Response builder:<br/>cards and system actions"]
end
subgraph shared["Shared (Go: internal/shared, .NET: Nirmitee.DaVinci.Common)"]
AUTH["JWT and JWKS auth,<br/>jti replay cache"]
FCL["FHIR client and JSON helpers"]
AUD["JSONL audit log"]
end
end
EHR -- "CDS Hooks call with JWT" --> HOST
HOST --> lib
VAL --> AUTH
ENG --> FCL
ENG --> RULES
RESP --> AUD
AUTH -. "fetch keys" .-> JWKS
FCL -. "when prefetch is missing" .-> FHIR
The same design carries over to the DTR and PAS servers, which are planned as separate repositories. The shared package will be extracted into a small module that all three use, and a combined host can then mount every module under its own prefix.
flowchart TB
subgraph repos["One repository and deployable server per IG"]
CRD["davinci-crd-server<br/>(this repository)"]
DTR["davinci-dtr-server<br/>(planned)"]
PAS["davinci-pas-server<br/>(planned)"]
end
COMMON["Shared module<br/>JWT and JWKS auth, FHIR helpers, audit log, config"]
COMBINED["Combined Burden Reduction server (planned)<br/>/crd, /dtr and /pas in one process"]
CRD --> COMMON
DTR --> COMMON
PAS --> COMMON
CRD --> COMBINED
DTR --> COMBINED
PAS --> COMBINED
Mounting the CRD module in your own host:
cfg, err := crd.LoadConfig("", os.Getenv)
if err != nil { log.Fatal(err) }
cfg.Prefix = "/crd"
handler, err := crd.NewHandler(cfg)
if err != nil { log.Fatal(err) }
mux.Handle("/crd/", handler) // /crd/v221/cds-services, /crd/v201/cds-servicesbuilder.Services.AddCrd(builder.Configuration);
app.MapCrd("/crd"); // /crd/v221/cds-services, /crd/v201/cds-services, /crd/healthThe full behavior contract both implementations follow is spec/SPEC.md. Implementation details are in go/README.md and dotnet/README.md.
git clone https://github.com/Nirmitee-tech/davinci-crd-server.git
cd davinci-crd-serverRequires Go 1.26.
cd go
go run ./cmd/crd-server
curl http://localhost:8081/v221/cds-servicesRequires the .NET 10 SDK.
cd dotnet
dotnet run --project src/Nirmitee.DaVinci.Crd.Host -- --urls http://0.0.0.0:8082
curl http://localhost:8082/v221/cds-servicesBuild from the repository root so the spec files are in the build context.
docker build -f go/Dockerfile -t davinci-crd-server-go .
docker run --rm -p 8081:8081 davinci-crd-server-go
docker build -f dotnet/Dockerfile -t davinci-crd-server-dotnet .
docker run --rm -p 8082:8082 davinci-crd-server-dotnetInside a container http://localhost is the container itself. When the CDS client hands out http://localhost/...
issuer or FHIR URLs (as a local Inferno does), rewrite them: -e CRD_URL_REWRITES="http://localhost|http://host.docker.internal"
for Go, or -e Crd__FetchUrlRewrites__0__From=http://localhost -e Crd__FetchUrlRewrites__0__To=http://host.docker.internal
for .NET.
Hook calls require a JWT from a trusted issuer. For a quick local try, start the server with authentication off (development only) and post one of the synthetic request bodies:
cd go
CRD_AUTH_DISABLED=true go run ./cmd/crd-server &
curl -s -X POST http://localhost:8081/v221/cds-services/order-sign-crd \
-H 'Content-Type: application/json' \
--data @../testdata/v221/hooks/order-sign/01-prefetch-hospital-bed-e0250.jsonThe sample bodies point fhirServer at a local Inferno instance for the resources that are not prefetched. Without
it the server cannot read them and answers with the technical-issues determination: a Coverage Information system
action stating that requirements could not be determined. The covered path with cards needs the mock EHR data, which
the unit tests (a fake FHIR server) and the Inferno runs provide.
Environment variables shared by both implementations:
| Variable | Default | Meaning |
|---|---|---|
PORT |
8081 (Go), 8082 (.NET) |
listen port |
CRD_RULES_PATH |
../spec/payer-rules.json |
payer rules file |
CRD_DATA_DIR |
./data |
data root; the audit log goes to {dir}/audit/YYYY-MM-DD.jsonl |
CRD_TRUSTED_ISSUERS |
local and public Inferno CRD issuers | comma-separated trusted iss values |
CRD_ISSUER_JWKS |
empty | JWKS overrides as iss=url;iss2=url2; default JWKS is {iss}/jwks.json |
CRD_REQUIRE_DISCOVERY_AUTH |
false |
require a client JWT on discovery |
CRD_AUTH_DISABLED |
false |
skip JWT checks on hooks; development only |
CRD_PUBLIC_BASE_URLS |
empty | comma-separated external base URLs accepted in aud, for example a tunnel URL |
CRD_FHIR_TIMEOUT_MS |
3000 |
timeout for each EHR FHIR fetch |
CRD_CLOCK_SKEW_SECONDS |
60 |
JWT time leeway |
The default trusted issuers are http://localhost/custom/crd_server, http://localhost/custom/crd_server_v221,
https://inferno.healthit.gov/suites/custom/crd_server and
https://inferno.healthit.gov/suites/custom/crd_server_v221. Replace them with your real CDS clients in production.
Implementation-specific settings:
| Setting | Go | .NET |
|---|---|---|
| Config file | -config path or CRD_CONFIG_FILE (YAML or JSON) |
appsettings.json, Crd section |
| Route prefix | CRD_PREFIX |
Crd__PathPrefix |
| Full listen address | CRD_LISTEN_ADDR |
--urls or ASPNETCORE_URLS |
| Outbound URL rewrites | CRD_URL_REWRITES (from|to pairs) |
Crd__FetchUrlRewrites__N__From, __To |
| Log level | CRD_LOG_LEVEL |
Logging__LogLevel__Default |
| Discovery documents | CRD_DISCOVERY_V221_PATH, CRD_DISCOVERY_V201_PATH |
built in, tested against spec/discovery-*.json |
The Docker images set CRD_RULES_PATH=/app/spec/payer-rules.json and CRD_DATA_DIR=/data.
The test kit is not part of this repository. You need Docker and Python 3.
# 1. clone and start the Inferno CRD test kit in the repository root (the folder is gitignored)
git clone https://github.com/inferno-framework/davinci-crd-test-kit.git
(cd davinci-crd-test-kit && docker compose up -d)
# 2. let the Inferno worker reach http://localhost callbacks
docker compose -f davinci-crd-test-kit/docker-compose.yml \
-f harness/docker-compose.localhost-proxy.yml up -d worker-localhost-proxy
# 3. run a server natively on the host (Go on 8081 or .NET on 8082), then run the suites
python3 harness/run_suite.py --version 2.2.1 --base-url http://host.docker.internal:8081/v221
python3 harness/run_suite.py --version 2.0.1 --base-url http://host.docker.internal:8081/v201Useful options: --groups 1,3.4,4.1 to run selected groups, --alg RS384 to switch the JWT algorithm, and
--inferno https://inferno.healthit.gov/suites to drive the public instance. Reports are written to
harness/reports/ and summarized in harness/LATEST.md. harness/build_testdata.py rebuilds testdata/ from the
kit presets.
To pass test 1.01 (TLS), expose the server over HTTPS, for example with ngrok http 8081, start the server with
CRD_PUBLIC_BASE_URLS=https://<ngrok-host>, and run the suites on the public Inferno instance with base URL
https://<ngrok-host>/v221 or /v201. The step-by-step guide is harness/tls_public_run.md.
go/ Go implementation: crd/ library, cmd/crd-server host, internal/shared auth, FHIR, audit, config
dotnet/ .NET 10 implementation: Nirmitee.DaVinci.Crd library, Crd.Host, Common, xUnit tests
spec/ SPEC.md behavior contract, payer-rules.json, discovery documents for 2.2.1 and 2.0.1
testdata/ synthetic hook request bodies, group 4 scenarios and mock EHR bundles (v221, v201)
harness/ scripts that run the Inferno suites headlessly and write reports
docs/results/ curated Inferno report summaries
- DTR server: payer-side Da Vinci Documentation Templates and Rules server (questionnaire package and adaptive
$next-question), Go and .NET, tested against the Inferno DTR server suites v2.2.0 and v2.0.1. - PAS server: Da Vinci Prior Authorization Support server (
$submit,$inquire, subscriptions and notifications), Go and .NET, tested against the Inferno PAS server suites v2.2.1 and v2.0.1. - Shared module: extract JWT and JWKS auth, FHIR helpers and the audit log into a module used by all three servers.
- Combined server: one Burden Reduction host that mounts CRD, DTR and PAS under their own prefixes.
Contributions are welcome. Behavior changes start in spec/SPEC.md and land in both implementations. See
CONTRIBUTING.md for setup, tests and the pull request checklist, and follow the
Code of Conduct. Report security issues privately as described in SECURITY.md.
All data in this repository is synthetic. Please never post real patient data in issues or pull requests.
Apache License 2.0. See LICENSE and NOTICE.
HL7, FHIR and the FHIR [FLAME DESIGN] are the registered trademarks of Health Level Seven International and their use does not constitute endorsement by HL7. The Inferno test kit is developed by the Inferno Framework team and is not redistributed here.
Built by Nirmitee.io.









