Integrating pVerify with FHIR: Step-by-Step Developer Guide
Technology Blogs

Integrating pVerify with FHIR: Step-by-Step Developer Guide

Mayuraj Dewangan
Software Engineer
TL;DR

pVerify + FHIR integration in 3 steps:

  • Create FHIR CoverageEligibilityRequest (patient, coverage, insurer, service type)
  • Convert CER → pVerify Eligibility Summary API format → OAuth client_credentials auth → POST /api/EligibilitySummary
  • Convert pVerify response → FHIR CoverageEligibilityResponse (handle non-EDI isPayerBackOffice payers separately)

 

In this blog, we explore how to integrate insurance and eligibility verification with an FHIR-based system using pVerify. Specifically, we’ll be leveraging pVerify’s Eligibility Summary API to achieve this.

What is pVerify?

As described on their platform, pVerify is “The leader in all-payer real-time patient insurance eligibility verification, offering instant API and batch solutions that combine technology with AI to simplify the patient care cycle for healthcare providers in medical, dental, and vision services.” In short, pVerify simplifies insurance and eligibility verification for healthcare providers. In this blog, we’ll focus on the Eligibility Summary API of pVerify’s REST API to handle patient eligibility checks.

Why Choose pVerify?

The standout feature of pVerify is its real-time eligibility verification. pVerify provides immediate access to patient insurance information while ensuring that no sensitive data is stored on their servers. All data transmissions are encrypted, providing a secure environment even on public networks.

Setting Up pVerify

  1. Account Setup
    🔺Visit pVerify’s website and follow the account creation process.
  2. Developer Access
    🔺After setting up, access the developer portal, where you’ll obtain the Client ID and Secret.
  3. Storing Credentials
    🔺Store your Client ID and Secret in a secure secret store. In this example, we will use Medplum’s clientApplication to store these parameters.

Using pVerify’s REST API

pVerify provides a RESTful API, but our focus will be on the Eligibility Summary API.

The Eligibility Summary API has the following signature:

Request:

curl --location 'https://api.pverify.com/api/EligibilitySummary' \
--header 'Authorization: Bearer {{access-token}}' \
--header 'Client-API-Id: {{client-api-id}}' \
--header 'Content-Type: application/json' \
--data '{
    "payerCode": "00192",
    "payerName": "UHC",
    "provider": {
        "firstName": "",
        "middleName": "",
        "lastName": " test name",
        "npi": "1234567890",
        "pin":"00000"
  },

    "subscriber": {
        "firstName": "fname",
        "dob": "mm/dd/yyyy",
        "lastName": "lname",
        "memberID": "123sfadfaf"
},

 "dependent": null,
 "isSubscriberPatient": "True",
 "doS_StartDate": "02/02/2021",
 "doS_EndDate": "02/02/2021",

 "PracticeTypeCode":"3",
 "referenceId":"Pat MRN",
 "Location":"Any location Name",
 "IncludeTextResponse":"false",
 "InternalId":"",
 "CustomerID":""
}'

This returns a response signature which is too large to present here. So we will be separating the important stuff as follows.

Using pVerify’s REST API

FHIR + pVerify Integration: 3-Step Approach

Our Goal

  1. For FHIR to pVerify integration, we’ll need to have the initial data in FHIR’s CoverageEligibilityRequest.
  2. Then we need to convert it into pVerify API format to fetch Eligibility Summary.
  3. And finally, we’ll convert the response back into FHIR’s  CoverageEligibilityResponse.

Plan of Action

Plan-of-Action

Start Your Integration Journey Today with pVerify and FHIR for Better Care!

Our Plan Comprises Three Parts:

  1. Creating FHIR’s CoverageEligibilityRequest.
  2. Converting CER to the valid pVerify Request and Calling the summary API.
  3. Converting pVerify’s response to CoverageEligibilityResponse and storing it.

We will be using Medplum, a healthcare/FHIR-based, open-source development platform. For ease of use.

With our approach in place, let’s start with the first part:

1. CoverageEligibilityRequest

CER is a standard FHIR resource. We can take input from the user or any other source and instantiate a CER object.

We’re using a form input to pass the data to the createResource Function.

const coverageEligibilityRequest: any = await medplum.createResource({
    resourceType: "CoverageEligibilityRequest",
    status: "active",
    purpose: ["validation"],
    patient: {
      reference: `Patient/${patientId}`,
    },
    servicedPeriod: {
      start: form.miscellaneous.fromDate.toISOString().split("T")[0],
      end: form.miscellaneous.toDate.toISOString().split("T")[0],
    },
    created: new Date().toISOString().split("T")[0],
    insurer: {
      reference: `Organization/${form.payer.id}`,
    },
    insurance: [
      {
        coverage: {
          reference: `Coverage/${coverage.id}`,
        },
      },
    ],
    provider: {
      reference: `Organization/${form.provider.id}`,
    },
    item: [
      {
        category: {
           coding: [
             {
               code: form.serviceType.id,
               display: serviceTypeMap.find(
                 (x: any) => x.value == form.serviceType.id
               )?.label,
             },
           ],
          },
        },
      ],
 });

This resource and its field should be tailored to the use case. Currently, we’re using the form inputs.

Note – Eligibility Summary supports 2 types of verification, Dependent and Subscriber, where the subscriber is straightforward as the patient is the plan holder.

For the Dependent, we’ll need to hold the subscriber’s information in the RelatedPerson resource which refers to the dependent patient.

As an example, here is the structure of a parent-child relation, where the child is dependent on the parent.

CoverageEligibilityRequest

This takes care of creating and storing CER in FHIR format.

2. Call the Summary API

Now that we have the CER we’ll need to convert it to a valid format and call the API.

Conversion can be done in this way:

const subscriberR = await (coverage?.subscriber ? medplum.readReference(coverage?.subscriber) : patient);
   const isSubscriberPatient = (subscriberR == patient);
   const dob = new Date(patient.birthDate)
   const patientInfo = {
           firstName: patient.name[0].given[0],
           lastName: patient.name[0].family,
           dob: formatDate(dob),
        };

   const subscriber = isSubscriberPatient
     ? {
        ...patientInfo,
        memberID: coverage.subscriberId
     }
     : {
       memberID: coverage.subscriberId
     };

   const dosStart = new Date(eRequest.servicedPeriod.start)
   const dosEnd = new Date(eRequest.servicedPeriod.end)

   const requestJSON = {
       payerCode: insurerIdentifier.value,
       payerName: insurer.name,
       provider: {
           firstName: '',
           middleName: '',
           lastName: provider.name,
           npi: providerIdentifier.value,
           pin: ''
       },
       subscriber: subscriber,
       dependent: isSubscriberPatient ? null : {patient: patientInfo},
       doS_StartDate: formatDate(dosStart),
       doS_EndDate: formatDate(dosEnd),
       isSubscriberPatient: isSubscriberPatient,
       location: provider.address[0].city,
       practiceTypeCode: eRequest.item[0].category.coding[0].code

}

Here eRequest is the CER, and subscriber’s reference is stored in the Coverage resource. Once we have this request, we’ll need to Authenticate and call the API.

AUTH:

It’s a simple OPENAPI oauth with client credentials, it should respond with the Bearer token.

const data = new URLSearchParams()
   data.append("Client_Id", clientID);
   data.append("Client_Secret", secret);
   data.append("grant_type", "client_credentials");

   const res = await fetch(`${pverifyAPIBase}/Token`, {
     method: 'POST',
     headers: {
       'Content-Type': 'application/x-www-form-urlencoded',
       // 'Accept': 'application/json,
     },
     body: data
})

Once we have the auth token, we can call the API with a converted Response.

Summary:

const res = await fetch(`${pverifyAPIBase}/api/EligibilitySummary`, {
     method: 'POST',
     headers: {
       'Content-Type': 'application/json',
       'Authorization': 'Bearer ' + token,
       'Client-API-Id': clientID
       // 'Accept': 'application/json,
     },
     body: JSON.stringify(requestJson)

3. CoverageEligibiltyResponse

Finally, we can convert the response back into the FHIR.

While doing this some points to consider:

  • The respective coverage needs to be updated.
  • For the various coding systems, FHIR provides an exhaustive list of standards.
  • If a code is not present in the FHIR, a list can be maintained for the codes as long as it is hosted in the system URL (this is not a standard approach but can work as a stopgap).
  • The benefits of the plan need to be mapped depending on the use case.

Handling for non-EDI:

  • Not all payers support instant eligibility and can take time to respond to queries, these payers are marked as non-EDI payers and should reflect in the response’s “isPayerBackoffice” field.
  • For non-EDI payers, the request ID needs to be stored and re-fetched by calling.
async function convertToCoverageResponse(res:any, eRequest:any, medplum:MedplumClient):Promise<any> {
   const identifier = [{
       system: codingSystemMap.pverify,
       value: String(res.RequestID),
   }
   ];

const efDate = res.PlanCoverageSummary?.EffectiveDate?.replaceAll(' ', '');
const exDate = res.PlanCoverageSummary?.ExpiryDateDate?.replaceAll(' ', '');


const startDate = efDate ? new Date(efDate).toISOString() : null;
const endDate = exDate ? new Date(exDate).toISOString() : null;


const coverage = await medplum.readReference(eRequest.insurance[0].coverage)
const updatedCoverage = await medplum.updateResource<any>({
    ...coverage,
    resourceType: 'Coverage',
    id: coverage.id,
    status: res.PlanCoverageSummary.Status == 'Active' ? 'active' : 'cancelled',
    type: {
        coding: [{
            system: codingSystemMap.actCode,
            code: "EHCPOL",
            display: "extended healthcare"
        }]
    },
    period: {
        start: startDate??undefined,
        end: endDate??undefined
    },
    class: [{
        type: {
            text: res.PlanCoverageSummary?.PolicyType??''
        },
        name: res.PlanCoverageSummary?.PlanName??'',
        value: res.PlanCoverageSummary?.PlanNumber??'--'
    }],
    network: res.PlanCoverageSummary?.PlanNetworkName??undefined

});

const CoverageEligibilityResponse = await medplum.createResource({
    resourceType: 'CoverageEligibilityResponse',
    identifier: identifier,
    status: res.PlanCoverageSummary.Status == 'Active' ? 'active' : 'cancelled',
    purpose: ['validation', 'benefits'],
    patient: eRequest.patient,
    servicedPeriod: eRequest.servicedPeriod,
    created: new Date().toISOString(),
    request: createReference(eRequest),
    outcome: res.IsPayerBackOffice
       ? 'queued'
       : res.ProcessedWithError
           ? 'error'
           : 'complete',
    insurer: eRequest.insurer,
    insurance: generateBenefitsList(res.ServiceDetails, updatedCoverage, res.PlanCoverageSummary.Status == 'Active'),
    extension: generateSummaryList(res)
  });

  return CoverageEligibilityResponse;

}

Finally, the entire flow should look like this:

GetEligibilitySummary

Conclusion

Integrating pVerify with an FHIR-based system enables healthcare providers to efficiently verify insurance eligibility. This guide outlines how to convert FHIR’s CoverageEligibilityRequest into a format suitable for pVerify’s Eligibility Summary API and then transform the response back into FHIR’s CoverageEligibilityResponse. This streamlined approach ensures real-time access to patient insurance information while maintaining data security through encrypted transmissions.

This integration significantly simplifies eligibility checks and enhances operational workflows in healthcare. As technology advances, such solutions will be vital for providers to deliver timely and accurate care amid the complexities of insurance verification. By following the outlined steps, organizations can effectively implement this integration and enjoy its many benefits.

Does pVerify support FHIR natively?

No. pVerify’s Eligibility Summary API uses its own REST format  not FHIR. This guide covers the conversion layer: FHIR CoverageEligibilityRequest in, pVerify API call, FHIR CoverageEligibilityResponse back out.

How do you handle non-EDI payers with pVerify?

Non-EDI payers don’t respond in real time. pVerify marks them with isPayerBackOffice: true in the response. Store the RequestID and poll for the result via a separate fetch rather than treating the initial call as a complete response.

Can this integration work without Medplum?

Yes. Medplum is used here as the FHIR server and clientApplication credential store the CoverageEligibilityRequest/Response resources and the pVerify conversion logic work with any FHIR R4-compliant server. Swap medplum.createResource() for your server’s equivalent.

Frequently Asked Questions

No. pVerify’s Eligibility Summary API uses its own REST format  not FHIR. This guide covers the conversion layer: FHIR CoverageEligibilityRequest in, pVerify API call, FHIR CoverageEligibilityResponse back out.

Non-EDI payers don’t respond in real time. pVerify marks them with isPayerBackOffice: true in the response. Store the RequestID and poll for the result via a separate fetch rather than treating the initial call as a complete response.

Yes. Medplum is used here as the FHIR server and clientApplication credential store the CoverageEligibilityRequest/Response resources and the pVerify conversion logic work with any FHIR R4-compliant server. Swap medplum.createResource() for your server’s equivalent.

Mayuraj Dewangan

Mayuraj Dewangan

Software Engineer

Connect Now

Mayuraj is a Full-Stack Developer with strong expertise in Node’S, React, Express, Angular, JavaScript, Python, Django, MongoDB, and SQL He currently works in the healthcare industry, where he leverages his technical skills to develop scaleable and robust solutions, and work with MERN architecture for fast API integration. Mayuraj has a track record of delivering end-to-end solutions across diverse industries, including Healthcare, Automotive and Fintech, and excels in both front-end and back-end development

Share This Blog

Read More Similar Blogs

Let’s #Transform Healthcare,# Together.

Partner with us to design, build, and scale digital solutions that drive better outcomes.

Location

Global Tech Teams LLC, 525 Washington Blvd, Industrious at Newport Tower, Jersey City, NJ 07310, United States.

Contact

+1 408 786 5974
contact@mindbowser.com
BOOK A QUICK CONSULTATION

Have a Healthcare Project in Mind?

Let’s discuss your goals, workflows, and next steps in a focused consultation call.

Calendar icon Schedule a Call

Contact form