CRD, DTR and PAS are one workflow.
Each stage hands the next one its input: a questionnaire canonical the payer chose, a completed response, an authorization number. And when a decision comes back A4, a status code is not the answer — a structured, correlated, retrievable documentation request is.
CMS-0057-F is the federal rule that requires Medicare Advantage, Medicaid, CHIP, and some exchange plans to offer FHIR APIs for patient access, provider access, payer-to-payer exchange, and prior authorization by January 1, 2027.
CRD, DTR and PAS are one workflow, not three endpoints
The three Da Vinci prior-authorization specifications are usually described separately, which makes them sound like three independent APIs a payer has to stand up. They are not. Each one hands the next its input, and an implementation that cannot pass that input along has built three demos rather than a workflow.
$submit to PAS $inquire.
CRD — is prior authorization required, and on what basis
A provider signs an order. A CDS Hooks service answers with a coverage determination carrying
covered, pa-needed, doc-needed and, where documentation is wanted,
a questionnaire canonical.
One implementation detail matters more than it sounds: a CRD determination can arrive in the
system action rather than in a card. A client that inspects only cards will read a
fully answered request as though nothing happened. An absent field must also be parsed as absent, never
defaulted — a missing pa-needed means the payer said nothing about prior
authorization, which is materially different from saying none is required.
DTR — the payer chooses the questionnaire; the requester follows it
The questionnaire canonical named by the coverage determination is requested from
Questionnaire/$questionnaire-package, and what comes back is a package containing that
questionnaire and the dependencies it declares.
Package completeness is checked as declared, not as assumed: the questionnaire is walked — library extension, answer value-set bindings, sub-questionnaire extensions, through nested items — and every canonical found must resolve inside the package. Demanding a Library or ValueSet that the questionnaire never asked for would fail a conformant server. Canonical versions are never normalised away either: a dependency present at a different version is reported as a version mismatch, not as missing, because calling it missing sends a reader looking for something that is sitting in the package.
PAS $submit — one authorization record
The completed documentation is submitted as a PAS Bundle carrying a Claim with
use = preauthorization. The response is a ClaimResponse on the PAS profile
carrying the authorization number as preAuthRef, an X12 278 review action, and — on a
denial — a coded reason rather than a bare "not medically necessary".
$inquire is a read projection, and it is enforced as one
An inquiry adds no store and no status field of its own. It reads the state $submit wrote
and the rest of the platform updates, through one controller and one response builder.
Read-only by contract, not by convention
The store interface exposes a single lookup method and no write method at all, and a structural test asserts it. An inquiry therefore cannot create a record, move a status, restart a decision clock, emit a duplicate transaction or cause a payer submission — however many times it is repeated. Status derives from the stored adjudication record rather than a live re-query, so an inquiry never turns into an outbound X12 transaction.
The authorization number alone is never enough
Authorization numbers are structured, and therefore guessable at the margins. An inquiry must also carry a corroborating key — the member, or the requesting provider NPI — and that key must match the stored record. A supplied key that does not match refuses even when another one does: naming the wrong member for a real authorization is guessing, and guessing must not get a different answer than a miss.
Deterministic status mapping, total over the status enum
| Authorization status | X12 278 | outcome | disposition |
|---|---|---|---|
| Submitted | — | queued | pending |
| InReview | — | queued | pending |
| Pended | A4 | queued | pended-additional-information |
| Approved | A1 | complete | approved |
| Modified | A2 | partial | modified |
| Denied | A3 | complete | denied |
| Expired | — | complete | expired |
| Cancelled | — | complete | cancelled |
outcome carries the coarse machine answer — still working, decided, partially decided
— and disposition the specific one, so a caller can distinguish pending from
pended for additional information from approved from denied. An unrecognised
status reads as still in progress rather than as an approval that cannot be vouched for.
Refusals do not leak which authorizations exist
Unknown authorization, wrong tenant and not-your-authorization all return one identical 404
OperationOutcome, so the identifier space cannot be probed. A malformed request is a
different matter and is described plainly — collapsing the two would tell a caller who forgot an
identifier that their authorization does not exist. The distinguishing category is kept in the audit
record instead, where an operator can act on it.
What actually has to happen after a payer answers A4
"Pended — additional information required" is the point where most prior-authorization integrations stop being a protocol exercise. A status code tells the provider that something is wanted. It does not tell them what, it does not correlate to anything they can retrieve, and it gives them nowhere to send an answer.
A working implementation needs all of the following, and Cloud Health Office implements the solicited CDex exchange to provide them:
A structured request, or none at all
A documentation request is raised only when the decision is Pended with review action
A4 and the decision names what documentation is wanted. A pended state alone
is not enough: manufacturing a request from it would put a question to the provider that no reviewer
posed. Each requested item carries an X12 PWK attachment-type code, a LOINC document-type code, the
service line it is about and whether it is mandatory — description supplements the codes, never
replaces them. A request with no items is refused at creation.
Something the provider can retrieve
The request is served as a FHIR Task on the CDex Task Attachment Request profile, at
GET Task/{id} and by search — by tracking id, or by code and focus to list every
cycle on one authorization. It is a projection computed on read from the one additional-information
record; nothing keeps a second copy.
Correlation that a caller cannot derive
The authorization number links the Task to the prior authorization the submitter already holds. The provider-facing tracking id is random rather than derived — it is one of the keys an intake must match, so deriving it from facts a caller already knows would hand it to anyone who knows them. A later cycle is a new record with its own sequence number.
A way back in, with controls
The provider answers with POST fhir/r4/$submit-attachment. Intake applies payload
controls, provider binding and idempotency, and an invalid submission is refused without
consuming the provider's one chance to answer — the request stays open. There is
deliberately no "invalid response" state.
A status transition that is honest
Documentation received returns the authorization to In Review — never directly
to approved. A cycle closed without the information reads as failed, not
completed: reporting both the same way would tell a provider their unanswered request had
been satisfied. Expiry is derived from the due date rather than stored, because nothing in this
repository sweeps due dates and a stored state nothing ever sets would be a lie in the data.
Repeatable inquiry behaviour
$inquire reports the resulting status without knowing anything about the exchange, and
every inquiry reads live committed state — no submission-time snapshot, no cache. A status
changed after submission is the status the next inquiry returns.
Retention, and why no sync job is needed
Retention is an explicit rule rather than an operational habit: retain until the last status change plus a configured period, with the CMS-0057-F one-year minimum enforced as a floor configuration cannot go under. The anchor is the last status change — never a read — so an inquiry cannot extend retention. Only terminal, past-boundary records are purgeable: Submitted, InReview and Pended records are never purged however old. Purge is a conditional delete, so a record that reopens mid-sweep survives and repeat runs are no-ops, and the sweep is disabled by default with a dry run available.
The freshness obligation needs no synchronisation job, because there is nothing to synchronise: prior-auth state is projected from the authoritative record at read time, the read seam exposes no write, and no replicated projection exists to drift. Pharmacy prior authorization is enforced as outside the CMS-0057-F medical scope rather than left as a documentation note, so drug items are excluded from the workflow and from what Patient Access serves.
What proves the above
Implementation evidence
- Scenarios
- PAS-01 CRD · PAS-02 DTR · PAS-03 submit · PAS-04 inquiry · PAS-05 coded denial · PAS-06 decision timeframe · PAS-07 CDex additional information · PAS-08 drug exclusion · PAT-03 prior-auth data retention
- IG family
- Da Vinci CRD / DTR / PAS STU 2.2.x · CDex solicited attachment
- Test data
- Synthetic. Decisions come from the Cloud Health Office rule store, not from a payer's production rules.
- Architecture docs
- prior-authorization.md · cdex-additional-information.md
- Pull requests
- #1147 drug exclusion · #1154 PAS
$inquire· #1155 prior-authorization retention · #1156 CDex additional-information round trip - Also exercised externally
- CRD, DTR and PAS
$submitare exercised against an independently developed HL7 Da Vinci implementation — see that evidence, which is kept separate from the acceptance status above
Prior-authorization scenarios from the latest published acceptance evidence, generated from the suite rather than typed into this page.
Loading the latest published CMS-0057-F acceptance evidence. It is generated in CI from the acceptance suite at a named source revision and committed to this repository, so the status shown here is the tested status rather than a claim typed into a page.
What is not proven here
- Acceptance evidence is not CMS certification, and a Passable status does not establish production readiness for a particular payer deployment.
- Synthetic data throughout. The coverage decisions exercised are Cloud Health Office's own rule content, not a plan's production medical policy.
- CQL is not executed. Where a DTR package carries a Library its structure is validated; its CQL is not run. This is package exchange, not rule evaluation.
- The CDex request is made available for retrieval, not pushed. There is no provider FHIR endpoint registry in this repository to POST a Task into.
- The CDex Task Data Request profile is deliberately not implemented — a payer querying a provider's clinical record is a different transaction from a pended prior authorization.
- Prior-authorization decisions in Augment mode depend on an external core adapter, and those adapters are documented stubs in this repository. See Replace vs Augment.
For the regulatory requirement rather than the implementation, the CRD, DTR and PAS guide on our sister reference site covers what the rule asks for.
Bring your own pended-authorization scenario.
The interesting question is rarely $submit. It is what your reviewers ask for, how it is coded, and who is allowed to answer.