Callout - Claims Advice Service
Claims offers advice on the pricing and benefit configuration for a combination of person or object, provider, procedure and many other attributes through the Advice Service. Oracle Health Insurance Authorizations can make use of this service to gain insight on provider contracts and benefit coverages and thereby make an informed decision to approve or deny an authorization.
This chapter illustrates examples on how the 'Advice' service can be leveraged by Oracle Health Insurance Authorizations.
Example - Is Authorization Required for the Procedure?
For certain authorization scenarios the system would first like to determine the need for an authorization and then inquire about provider contract and coverage details. This is because at times an authorization is needed for a procedure only when it is not accompanied by specific diagnoses or other procedures. For example; physical therapy during and after hospitalization stay for a knee replacement surgery could be covered in full for an in-network provider without prior authorization, but physical therapy sessions at a private clinic for a chronic joint condition may require a prior authorization for the procedure to be covered in full.
Oracle Health Insurance Authorizations can make a call out to Claims Advice Service. This service can then send back the response with the information whether an authorization is required or not for the given procedure(s). It also provides detail on the condition under which an authorization is required.
For details on the "Claims Advice Service" section refer to the Operations chapter in the Claims Developer Guide.
Suppose the following authorization request is entered in the system:
Form |
CHRONICMEDAUT |
|---|---|
Type |
Authorization |
Requested By |
AE 51247712 (Dr. Smith) |
Requested For |
19000123 (J. William) |
Provider Group Scope |
In |
Location Provider |
AL 51233444 ( ZHK Clinic) |
Location Type |
14 (Independent Clinic) |
Start Date |
2017-01-01 |
End Date |
2017-03-31 |
Authorization Line |
Procedure 01.091 (Physiotherapy Session) ~20 units |
Authorization Diagnosis |
ID.810 CLAVICLE FRACTURE |
An authorization is requested for 20 physical therapy sessions at a private clinic. In order to know if an authorization is needed or not a call out rule has to be set up. The call out rule makes a web service call to Claims Advice Service, which then returns the information needed by the authorization system.
The call out rule is configured as:
Code |
ISAUTHNEEDED |
|---|---|
Description |
Determines if the authorization needed check is required or not |
Condition |
ISAUTHNEEDED |
Function |
AUTHNEEDEDCALLOUT |
Response Definition Code |
AUTHNEEDEDCHECK |
Here, the field response definition code is a dynamic field of the call out rule. It holds the response definition code with which the Claims Advice Service must be invoked.
The call out function dynamic logic needs to create an Advice Request and process the Advice Response:
import groovy.json.*
def builder = new groovy.json.JsonBuilder()
def productList=[]
authorization.policyProductList.each { r -> productList.add(r.product.code) }
def request = builder {
procedure(flexCodeDefinitionCode:authorizationLineList[0].procedure.flexCodeSystem.code,
code:authorizationLineList[0].procedure.code)
insurableEntity(code:authorization.person.code, type:"person")
productCodeList (productList)
locationTypeCode (authorization.locationTypeCode)
diagnosis (flexCodeDefinitionCode:authorizationDiagnosisList[0].diagnosis.flexCodeSystem.code,
code:authorizationDiagnosisList[0].diagnosis.code)
locationProvider(flexCodeDefinitionCode:authorization.locationProvider.flexCodeSystem.code,
code :authorization.locationProvider.code)
parameterList ([key:"benSpecCategory", value:authorization.authorizationForm.code] )
serviceDate(authorization.startDate)
}
String response = initCallOut(WebTarget.class)
.path("post")
.request("application/json")
.header("adviceResponseDefinitionCode", calloutRule.responseDefinitionCode)
.buildPost(Entity.json(builder.toString()))
.invoke()
.readEntity(String.class)
-- Parsing of the claims response
def result = new JsonSlurper().parseText(response)
boolean isAuthNeeded
def noUnitswhenAuthisNeeded = 0
--Check if periods are defined or not through custom function periodsDefined
--result.authorizationRegime.authorizationRegimePeriod[0].period == null && result.authorizationRegime.authorizationRegimePeriod.size() == 1
if (!periodsDefined(result)) {
if (result.authorizationRegime.authorizationRegimePeriod[0].authTranches) {
for (it in result.authorizationRegime.authorizationRegimePeriod[0].authTranches) {
-- go over tranches
noUnitswhenAuthisNeeded = noUnitswhenAuthisNeeded + it.maximumNumber
if (it.authorizationNeeded == "Y") {
isAuthNeeded = true
}
if (isAuthNeeded && (noUnitswhenAuthisNeeded <= authorization.authorizationLine[0].requestedNumberOfUnits)){
authorization.authorizationLine[0].isAuthorizationNeeded = isAuthNeeded
break
}
}
}
}
The request that is sent to the advice service:
{"procedure":{"flexCodeDefinitionCode":"01","code":"091"},
"insurableEntity":{"code":"19000123","type":"person"},
"productCodeList":["GOLD"],
"locationTypeCode":"14",
"diagnosis":{"flexCodeDefinitionCode":"ID-SAMPLE","code":"814"},
"locationProvider":{"flexCodeDefinitionCode":"AL","code":"51233444"},
"parameterList":[{"key":"authorizationForm","value":"CHRONICMEDAUT"}],
"serviceDate":"2017-01-01"
}
On the Claims side the Advice Response Definition is set up as:
Code |
AUTHNEEDEDCHECK |
|---|---|
Description |
Determines if the authorization is needed or not |
Response Function |
AUTHNEEDEDCHECK |
Suppose that the advice service finds the following product benefit specification of sub type - Authorization
Product Code |
GOLD |
|---|---|
Product Benefit Specifications |
|
Code |
BENAUTH001 |
Subtype |
AUTH |
Product Scope |
Either |
Procedure Group |
In.PhysicalTherapy |
The authorization regime is configured as follows:
Type |
Authorization |
|---|---|
Code |
AUTH001 |
Authorization Regime Tranches |
|
Tranch 1: Value ~ Auth Needed |
10-No Auth Needed |
Tranch 2: Value ~ Auth Needed |
Auth Needed |
The response function AUTHNEEDEDCHECK reads the authorization regime and send the details to the authorization system. In this example the parameters sent from authorization are used to filter out the authorization regime with the 'prodBenefitSpecsCategory' dynamic field property on the productBenefitSpecification.
import groovy.json.*
def pbsAuthList = productBenefitSpecificationMap["Authorization"]
if (pbsAuthList) {
def pbsAuth = pbsAuthList.find { it.prodBenefitSpecsCategory= adviceRequest.parameterList.find{it.key="authorizationForm"}.value
}
if (pbsAuth != null) {
def authRegime = pbsAuth.benefitSpecification.authorizationRegime
class AuthTranche {
def sequence
def maximumNumber
def authorizationNeeded
}
class AuthPeriod {
def period
def unitOfMeasure
def reference
def authTranches=[]
}
def authPeriods = []
authRegime.authorizationRegimePeriodList.each { authRegPeriod ->
def authPeriod = new AuthPeriod(period:authRegPeriod.period,
unitOfMeasure:authRegPeriod.periodUom,
reference:authRegime.reference)
authRegPeriod.authorizationRegimeTrancheList.each { authRegPerTranche ->
def authTranch = new AuthTranche( sequence:authRegPerTranche.sequence,
maximumNumber:authRegPerTranche.maximumNumber,
authorizationNeeded:authRegPerTranche.authorizationNeeded)
authPeriod.authTranches << authTranch
authPeriods <<authPeriod
}
}
def builder = new groovy.json.JsonBuilder()
def request = builder { authorizationRegime (authorizationRegimePeriod:authPeriods) }
return builder.toString()
}
}
The response returned by the advice service to Oracle Health Insurance Authorizations would be:
{"authorizationRegime":
{"authorizationRegimePeriod":[
{"period":"",
"unitOfMeasure":"",
"authTranches":[{"maximumNumber":"10","authorizationNeeded":"N","sequence":"1"}
{"maximumNumber":"","authorizationNeeded":"Y","sequence":"2"],
"reference":""}]
}
}
On the authorization side, the call out function checks when the authorization is needed and accordingly sets the attribute 'isAuthNeeded' on the procedure.
Example: What is the Provider Group Scope?
The provider group scope information can help the authorization system to make an appropriate decision; for example, based on whether the service provider is IN or OUT; there can be different process rules for the authorization to be approved or denied. If the provider is out of network; then the insurer might need more details about the provider before the authorization can be approved.
In order to determine if the provider group scope is IN or OUT; a callout rule is setup is
Code |
PROVIDERGROUPSCOPE |
|---|---|
Description |
Determines if the service provider is IN or OUT |
Condition |
PROVGRPSCOPECHECKNEEDED |
Function |
PROVGRPSCOPECHECK |
Response definition Code |
PROVIDERSCOPECHECK |
PROVGRPSCOPECHECK function is set up as:
import groovy.json.*
def builder = new groovy.json.JsonBuilder()
def productList=[]
authorization.policyProductList.each { r -> productList.add(r.product.code) }
def request = builder {
procedure(flexCodeDefinitionCode:authorizationLineList[0].procedure.flexCodeSystem.code,
code:authorizationLineList[0].procedure.code)
insurableEntity(code:authorization.person.code, type:"person")
productCodeList (productList)
locationTypeCode (authorization.locationTypeCode)
diagnosis (flexCodeDefinitionCode:authorizationDiagnosisList[0].diagnosis.flexCodeSystem.code,
code:authorizationDiagnosisList[0].diagnosis.code)
locationProvider(flexCodeDefinitionCode : authorization.locationProvider.flexCodeSystem.code,
code :authorization.locationProvider.code)
parameterList ([key:"authorizationForm", value:authorization.authorizationForm.code])
startDate (authorization.startDate)
endDate (authorization.startDate)
}
String response = initCallOut(WebTarget.class)
.path("post")
.request("application/json")
.header("adviceResponseDefinitionCode, calloutRule.responseDefinitionCode)
.buildPost(Entity.json(builder.toString()))
.invoke()
.readEntity(String.class)
--Parsing of the response
def result = new JsonSlurper().parseText(response)
authorization.adviceProviderGroupScope = result.providerGroupScope
authorization.addMessage(result.message.code, result.message.args)
The provider group scope on the benefit specification is also the provider group scope for the provider of the service. The advice service response definition is set up as:
import groovy.json.*
def pbsCovList = productBenefitSpecificationMap["Coverage"]
def providerGroupScope
if (pbsCovList) {
providerGroupScope = pbsCovList[0].benefitSpecification.productProviderGroupScope
}
def builder = new groovy.json.JsonBuilder()
def request = builder {
providerNetwork(providerGroupScope:providerGroupScope )
message( code:"ADV-COMMON-MSG-001", args:[{"The provider group scope is "+providerGroupScope }]}
return builder.toString()
The advice service passes the provider group scope information to the authorization system. This information is then used for further processing of the authorization.
The response returned by the advice service to Oracle Health Insurance Authorizations:
{
"adviceProviderGroupScope":"OUT"
"message": {
"code":"ADV-COMMON-MSG-001"
"value":["ProviderGroupScope Advice","The provider group scope is OUT"]
}
}
-- message ADV-COMMON-MSG-001 is setup up as "The \{0} is \{1}"
Based on the response the call out function updates the field Advice Provider Group Scope (dynamic field) on the authorization.
Example - What Limits are Defined?
The advice service can be implemented to get more insight on the limits that are defined in the claims system. There are two possible triggers for a limit to apply - either the presence of a count-towards-limit record or a product benefit specification limit that is valid on the as-of date and that specifies a cover withhold category. The Authorization system can get details on limits that are defined and also obtain the configuration information like 1) What is the maximum 2) Is there a renewal? etc. This information can then be used to drive the processing of an authorization request.
The sample advice service response function defined below looks up the details on the limit; it also looks up the existing consumptions in the claims systems and provides the details to the authorization system.
import groovy.json.*
def pbsCovList = productBenefitSpecificationMap["Coverage"]
if (pbsCovList) {
def pbdCovLimitList = pbsCovList[0].productBenefitSpecificationLimitList
if (pbdCovLimitList) {
def pbdCovLimit = pbdCovLimitList[0]
-- read consumption using predefined method
def insurableEntity = lookUpInsurableEntity(adviceRequest.insurableEntity.code,
adviceRequest.insurableEntity.type)
def limitCounterPeriod = pbdCovLimit.limit.getLimitCounterPeriod(
adviceRequest.serviceDate,
insurableEntity)
def currentConsumptionAmount = limitCounterPeriod.currentAmount.amount
def currentConsumptionCurr = limitCounterPeriod.currentAmount.currencyCode
def builder = new groovy.json.JsonBuilder()
def request = builder {
productBenefitSpecification(
-- set required product benefits specs attributes
productBenefitSpecificationLimit(
-- set required product benefits specs limit attributes
limit (
-- set required limit attributes
consumption ( utilizedAmount ( value:currentConsumptionAmount , currency:currentConsumptionCurr)
)
)
)
}
return builder.toString()
}
}
The authorization system receives the following response
{
productBenefitSpecification:{"productCode:"Basic",
"productBenefitSpecificationLimit":{
"aliasCode":"PC0011_13_AC1",
"maximumAmount":{"currency":"USD",
"value":5000 },
"limit": { "acrossProducts":false,
"acrossProviders":true,
"action":"C",
"code":"PC0011_13_L2",
"limitLevel":"M",
"reference":"Y",
"renewalPeriod":1,
"renewalPeriodUom":"Y",
"type":"D",
"descr":"Individual Max for radiology services",
"consumption":{"utilizedAmount":{"currency": "USD", "value":1000}}
}
}
}
The call out function parses this response.
The consumed limit is then subtracted from the policy product parameter value provided by the enrollment system to get the remaining height of the limit. This value is then set on a dynamic field 'limitNotUsed ' of the authorization line.
--Parsing of the response
def result = new JsonSlurper().parseText(response)
selectPolicyProduct = authorization.policyProduct.find({it.product.code = result.productBenefitSpecification.productCode})
policyParam = selectPolicyProduct.policyProductParameterList.find({it.aliasCode = result.productBenefitSpecification.productBenefitSpecificationLimit.aliasCode})
authorization.authorizationLineList[0].limitNotUsed =
policyParam.amount- result.productBenefitSpecification.productBenefitSpecificationLimit.limit.consumption.utilizedAmount.value
Example - How much is Allowed to a Provider and How Much is Covered?
The advice service can provide details on the reimbursement method/rules and coverages. For example, the charged amount that could become eligible for the provider / procedure combination can be obtained by using the advice service. The service can also provide details on the coverage regime like the amount or percentage covered and withheld.
The sample advice service response function defined below looks up the details on the provider pricing clauses. It also looks up the coverage regimes and provides the details on the coverage.
import groovy.json.*
def ppcChargedAmountList = providerPricingClauseMap["ChargedAmount"]
def allowedAmount
def coveredAmount
if (ppcChargedAmountList) {
requestedAmount = adviceRequest.parameterList.find {it.key="requestedAmount"}.value
if (ppcChargedAmountList[0].percentage == null) {
allowedAmount = requestedAmount
} else {
allowedAmount = ppcChargedAmountList[0].percentage * 0.01 * requestedAmount
}
def pbsCovList = productBenefitSpecificationMap["Coverage"]
if (pbsCovList) {
def coverageRegimePeriod = pbsCovList[0].benefitSpecification.coverageRegime.coverageRegimePeriodList[0]
def coverageRegimePeriodTranche = coverageRegimePeriod.coverageRegimePeriodTrancheList[0]
def coverWithholdRule = coverWithholdRuleList.find { it.coverWithholdCategory.action == "C" }
coveredAmount = coverWithholdRule.percentage * 0.01 * allowedAmount
}
def builder = new groovy.json.JsonBuilder()
def response = builder {
allowedAmount(currency : "USD" ,
value : allowedAmount)
coveredAmount(currency : "USD" ,
value : coveredAmount)
}
return builder.toString()
The authorization system receives the following response
{
"allowedAmount":{"currency":"USD",
"value":2500},
"coveredAmount":{"currency":"USD",
"value":2300}
}
Example - Is There any Waiting Period Configured?
It is possible that a procedure is fully covered, however there is a waiting period associated to it before it can be consumed. The claims advice service provides information about the waiting periods configured in the claims system.
This sample groovy reads the waiting period regime and passes the configuration information to the authorization.
import groovy.json.*
def pbsWaitingList = productBenefitSpecificationMap["WaitingPeriod"]
def builder = new groovy.json.JsonBuilder()
if (pbsWaitingList) {
def response = builder {
productBenefitSpecification (
-- set required product benefits specs attributes
waitingPeriodRegime(period:pbsWaitingList[0].benefitSpecification.waitingPeriodRegime.period,
periodUom:pbsWaitingList[0].benefitSpecification.waitingPeriodRegime.periodUom)
)
}
return builder.toString()
}
The call out function parses the response from claims advice service and checks if the waiting period applies or not. A message is attached to authorization if a waiting period applies.
--Parsing of the response on the auth side
import groovy.time.TimeCategory
def result = new JsonSlurper().parseText(response)
selectedPolicyProduct = authorization.policyProduct.find { it.product.code = result.productBenefitSpecification.productCode }
def periodEndDate
def periodUom = result.productBenefitSpecification.waitingPeriodRegime.periodUom
use(TimeCategory) {
if(periodUom =="D"){
periodEndDate= selectedPolicyProduct.contractDate + result.productBenefitSpecification.waitingPeriodRegime.period.day
else if(periodUom =="M"){
periodEndDate= selectedPolicyProduct.contractDate + result.productBenefitSpecification.waitingPeriodRegime.period.month}
else {
periodEndDate= selectedPolicyProduct.contractDate + result.productBenefitSpecification.waitingPeriodRegime.period.year }
}
if (authorization.startDate > selectedPolicyProduct.contractDate && authorization.startDate < periodEndDate ){
def args =[result.productBenefitSpecification.waitingPeriodRegim.period, result.productBenefitSpecification.waitingPeriodRegime.periodUom]
authorization.addMessage("AUTH_WAITING_PERIOD", args)
}
A validation rule can be set up to check for such a message and an authorization can be pended or denied.
Example - Multiple Procedures
The authorization request may contain multiple procedures; for example in the case of hospital authorizations the advice service is invoked multiple times from the call out rule.
Consider the following authorization request
Form |
HOSPITALAUTH |
|---|---|
Type |
Authorization |
Reqested By |
AE-51247712 (Dr. John) |
Requested For |
19000123 (J. Swart) |
Provider Group Scope |
In |
Loaction Provider |
AL-51233444 ( MNL Hospital) |
Location Type |
18 (Hospital) |
Start Date |
2017-01-01 |
End Date |
2017-03-31 |
Authorization Line |
Procedure 08.860 (Surgery) ~ Requested amount $ 10000 |
Authorization Line |
Procedure 06.222( General Care) ~ 5 Days |
Authorization Line |
Procedure 03.145 (Radiology) |
Authorization Diagnoses |
547 (Acute appendicitis) |
The callout rule can be implemented as:
import groovy.json.*
def builder = new groovy.json.JsonBuilder()
def productList=[]
authorization.policyProductList.each {r ->productList.add(r.product.code) }
authorization.authorizationLineList.each {
def request = builder {
procedure(flexCodeDefinitionCode:it.procedure.flexCodeSystem.code,
code:it.procedure.code)
insurableEntity(code:authorization.person.code, type:"person")
productCodeList (productList)
locationTypeCode (authorization.locationTypeCode)
diagnosis (flexCodeDefinitionCode:authorizationDiagnosisList[0].diagnosis.flexCodeSystem.code,
code:authorizationDiagnosisList[0].diagnosis.code)
locationProvider(flexCodeDefinitionCode : authorization.locationProvider.flexCodeSystem.code,
code :authorization.locationProvider.code)
parameterList ([key:"authorizationForm", value:authorization.authorizationForm.code ] )
startDate (authorization.startDate)
endDate (authorization.startDate)
}
String response = initCallOut(WebTarget.class)
.path("post")
.request("application/json")
.header("adviceResponseDefinitionCode", calloutRule.responseDefinitionCode)
.buildPost(Entity.json(builder.toString()))
.invoke()
.readEntity(String.class)
def result = new JsonSlurper().parseText(response)
it.procedure.authNeeded = result.isAuthNeeded
authorization.addMessage(result.message.code, result.message.args)
}
Here, the response of each invocation to the advice service is processed; the message returned by the advice service for each procedure is added to the authorization.