Callout - Claims Advice Service

OHI Claims Adjudication and Pricing offers an 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 OHI Claims Adjudication and Pricing 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 refer to the Operations section in the OHI Claims Adjudication and Pricing Integration 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

01-01-2017

End Date

31-03-2017

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 OHI Claims Adjudication and Pricing 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 OHI Claims Adjudication and Pricing 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 OHI Claims Adjudication and Pricing 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

01-01-2017

End Date

31-03-2017

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.