Cerbo has built-in options for creating and transmitting HL7 ADT or DFT messages to third-parties (generally billing platforms for submitting to insurance) but it is also fairly easy for a technical team to create these using our API. This article will focus on DFT generation (claims submission) but the calls are applicable to most other HL7 message types.
Generally creating a DFT claim would involve listening to soap.modified webhooks to determine when an encounter note is signed (you can use other triggers if appropriate). Once you've determined that a specific encounter note is ready to generate an DFT claim for, you just need the encounter ID (data.id in the soap webhook) in order to get all the data you need to create a full DFT. The necessary data will be retrieved using four API GET endpoints. For the sake of documentation, each of these endpoints are represented by a one-letter variable below:
s = soap (encounter) endpoint: /api/v1/encounters/[encounter_id]
p = patient endpoint: /api/v1/patients/[s.pt_id]
f = financials endpoint for a list (array) of encounter charges: /api/v1/patients/[p.id]/encounters/[s.id]/charges
u = user (provider) endpoint: /api/v1/users/[s.owner] (note: this may be worth caching as this data will rarely change per user)
Example raw output for these API endpoints are linked to in this article for reference. Once you have the data from those endpoints you can contruct your DFT message by following these steps:
1. Create the MSH segments: Most of these fields will be generated by the partner organization, not Cerbo:
MSH|^~\&|MDHQEMR|CLIENTFACILITY|1100|NULL|[PartnerTimestamp]|[PartnerCreates]|DFT^P03|[PartnerCreates]|P|2.3.1|
2. Create the EVN segment: Likewise, the data for this will not be coming from Cerbo:
EVN|P03|s.date_of_service or PartnerTimestamp^S|
3. Create the PID (patient) segment:
PID|1|p.id|||p.last_name^p.first_name^p.middle_name||p.dob|p.sex|||p.address1^p.address2^p.city^p.state^p.zip||p.phone_mobile^^^p.email1|||||ACCTNUM^^^P||
4. Create the PV1 (visit) segment:
PV1|1||[*see encounter type note]||||u.npi^u.last_name^u.first_name||^^||||||||||s.id||||||||||||||||||||[*see servicing facility note]|
* Encounter type note: Place of service code and description for PV1 should be calculated from s.encounter_type - you can create a map of these, which are generally 2-letter prefixes and can be defined by each practice to create visit-types and visit-location-codes which are selected from when creating an encounter.
5. Create each of the FT1 (charge) segments:
For each charge (c) defined in in f.data, determine if the charge should be submittable to insurance by checking c.billing_rules.add_to_insurance_claim. If `true` then create the corresponding FT1 segment:
FT1|[segment #]|c.id||c.transaction_date||CG|c.charge_master_details.id|c.name||c.quantity||c.charge_master_details.retail or c.amount/c.quantity|||||||c.billing_rules.justifying_diagnoses|||c.charge_master_details.wholesale|||c.billing_rules.cpt_code|c.billing_rules.cpt_modifiers
6. Create the DG1 (diagnostic) segments:
For each diagnosis (d) defined in in s.assessments, ensure that the d.icd_version is 10 (or whatever version is required for your country of operation) and include the DG1 segment
DG1|[segment #]||d.code^^["I"+d.icd_version]||
7. Create the IN1 (insurance) segment(s):
Note that patients can have more than one insurance on file. These additional payors will be available on the patient (p) API response as secondary/tertiary/etc `insurance` objects which can be used to create additional IN1 segments if appropriate.
IN1|1||[*see insurance plan id]^|p.insurance.insurance_plan|p.insurance.insurance_address^p.insurance.insurance_address2^p.insurance.insurance_city^p.insurance.insurance_state^p.insurance.insurance_zip|||p.insurance.insurance_group||||||||p.insurance.insured_name_last^p.insurance.insured_name_first|[*calculate from p.insurance.relationship_to_insured]|p.insurance.insured_dob|p.insurance.insured_address^^p.insurance.insured_city^p.insurance.insured_state^p.insurance.insured_zip^||||||||||||N|||||p.insurance.insurance_id|||||||p.insurance.insured_sex|
*Servicing facility note: Code can be hard-coded per client, or based on s.encounter_type (or in rare use-cases, c.location)
*Insurance Plan ID: IN1.3 is not directly exposed in the API, but it should be calculated from p.insurance.insurance_plan or parsing the p.insurance.insurance_id (member ID) depending on partner capabilities.
*Insurance relationship code is a plaintext entry and should be mapped to a code: "Self"=18, "Spouse"=1, "Dependent"=19 (generally child), "Other"=G8