The Coverage Requirements Discovery (CRD) module in Smile Digital Health facilitates interactions between the Electronic Medical Record (EMR) systems, referred to as the Client, and the payer systems to determine prior authorization requirements for specific healthcare services to be provided to a patient.
Built on the Fast Healthcare Interoperability Resources (FHIR®) standards, Prior Auth CRD aligns with the HL7 Da Vinci Coverage Requirements Discovery (CRD) implementation guidelines (IG). The Prior Auth CRD module supports FHIR® version R4 and enhances the prior authorization workflow with several key features:
The Prior Auth CRD module registers one or more CDS services to the CDS hooks module dependency. These services are available at the discovery url of the CDS hooks module i.e. {{baseCDSHooksModuleUrl}}/cds-services
. This list includes:
davinci-crd.configuration-options
extension.JS functions
or custom Java processors/endpoints/components
, which can be used in camel routes.Java
object or in a String
format.v2025.05
, camel route will be used for evaluation of a prior auth request.priorAuthCrdContextJson
.Java
object or in a String
format.crdApplyProcessor
in their camel route to use CQL engine to evaluate the prior auth request.
crdApplyProcessor
requires a route
parameter named planDefinitionId
, which will be used to perform the PlanDefinition/$apply
call.<route>
<from uri="direct:start"/>
<to uri="smile:prior_auth_crd_module_id/crdApplyProcessor?planDefinitionId=plan_definition_fhir_resource_id"/>
</route>
/*-
* #%L
* Smile CDR - CDR
* %%
* Copyright (C) 2016 - 2025 Smile CDR, Inc.
* %%
* All rights reserved.
* #L%
*/
package com.smilecdr.demo.priorauthcrd;
import ca.cdr.api.fhir.interceptor.CdrHook;
import ca.cdr.api.fhir.interceptor.CdrPointcut;
import ca.cdr.api.priorauth.PriorAuthCrdContextJson;
import ca.uhn.fhir.interceptor.api.Interceptor;
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.rest.api.server.cdshooks.CdsServiceRequestJson;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import jakarta.annotation.Nonnull;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Coverage;
import org.hl7.fhir.r4.model.Identifier;
import org.hl7.fhir.r4.model.ResourceType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
/**
* Sample interceptor codebase which allows getting Payer Patient ID by matching Provider and Payer Coverage resources
* based off Identifier
*/
@SuppressWarnings({"unused"})
@Interceptor
public class PriorAuthCRDInterceptorTemplate {
private static final Logger ourLog = LoggerFactory.getLogger(PriorAuthCRDInterceptorTemplate.class);
private static final String IDENTIFIER_SYSTEM = "http://acme.org/fhir-ns/payer-coverage-identifier-system";
@Autowired
@Qualifier("paCrdDaoRegistry")
private DaoRegistry myDaoRegistry;
@CdrHook(CdrPointcut.PRIOR_AUTH_CRD_GATHER_CONTEXT)
public void gatherContext(
@Nonnull CdsServiceRequestJson theCdsServiceRequestJson,
@Nonnull PriorAuthCrdContextJson thePriorAuthCrdContextJson) {
ourLog.info("Interceptor PRIOR_AUTH_CRD_GATHER_CONTEXT - started");
final Bundle coverageBundle = (Bundle) theCdsServiceRequestJson.getPrefetch("coverageBundle");
final Identifier coverageIdentifier = getProviderCoverageIdentifier(coverageBundle);
final String payerPatientId = getPayerPatientId(coverageIdentifier);
thePriorAuthCrdContextJson.setPayerPatientId(payerPatientId);
ourLog.info("Interceptor PRIOR_AUTH_CRD_GATHER_CONTEXT - ended");
}
/**
* Get the provider Coverage identifier from provider Coverage bundle found in prefetch of CDS hooks request
* @param theRequest the provider Coverage bundle
* @return provider coverage identifier
*/
@Nonnull
private Identifier getProviderCoverageIdentifier(@Nonnull Bundle theRequest) {
final Coverage providerCoverage = theRequest.getEntry().stream()
.map(Bundle.BundleEntryComponent::getResource)
.filter(resource -> resource.getResourceType().equals(ResourceType.Coverage))
.map(Coverage.class::cast)
.findFirst()
.orElseThrow(() -> new UnprocessableEntityException("Coverage resource not found"));
return providerCoverage.getIdentifier().stream()
.filter(identifier -> identifier.getSystem().equals(IDENTIFIER_SYSTEM))
.findFirst()
.orElseThrow(() -> new UnprocessableEntityException("Identifier with specified system not found"));
}
/**
* Get the Payer Patient ID in context
* @param theCoverageIdentifier provider coverage identifier
* @return Payer Patient ID
*/
@Nonnull
private String getPayerPatientId(@Nonnull Identifier theCoverageIdentifier) {
final SearchParameterMap searchParameterMap = getSearchParameterMap(theCoverageIdentifier);
final IFhirResourceDao<Coverage> coverageResourceDao = myDaoRegistry.getResourceDao(Coverage.class);
final IBundleProvider search = coverageResourceDao.search(searchParameterMap, new SystemRequestDetails());
return ((Coverage) search.getAllResources().get(0)).getBeneficiary().getReference();
}
/**
* Build SearchParameterMap for Dao search on Coverage identifier
* @param theCoverageIdentifier provider coverage identifier
* @return SearchParameterMap
*/
@Nonnull
private SearchParameterMap getSearchParameterMap(@Nonnull Identifier theCoverageIdentifier) {
final TokenParam tokenParam =
new TokenParam(theCoverageIdentifier.getSystem(), theCoverageIdentifier.getValue());
final SearchParameterMap searchParameterMap = new SearchParameterMap();
searchParameterMap.add(Coverage.SP_IDENTIFIER, tokenParam);
return searchParameterMap;
}
}
PlanDefinition/$apply
operation.v2025.08
, this interceptor will be removed as the Patient in context can be set in camel properties.