Extracts claim processing summaries and benefit explanations from insurance statements.
An Explanation of Benefits (EOB) is a document issued by a health insurance plan that details how a submitted medical claim was processed, including the charges billed, amounts allowed, benefits applied, and the patient's financial responsibility. This template takes in EOBs and outputs JSON (.json) with structured claim and member data including service line items, financial totals, deductible and out-of-pocket status, and benefit period details per the extraction schema by using Extend's Extract primitives.
Pulls a defined set of fields from the document and returns them as structured JSON matching a schema.
schemacustom schema — 20 fieldschangedadditionalPropertiesfalsechangedproperties.amount_allowed.additionalPropertiesfalsechangedproperties.amount_allowed.description"The total amount allowed by the health plan for the services provided, after discounts and reductions. This is the maximum amount considered for payment."changedproperties.amount_allowed.extend:type"currency"changedproperties.amount_allowed.properties.amount.type["number","null"]changedproperties.amount_allowed.properties.iso_4217_currency_code.type["string","null"]changedproperties.amount_allowed.required["amount","iso_4217_currency_code"]changedproperties.amount_allowed.type"object"changedproperties.amount_billed.additionalPropertiesfalsechangedproperties.amount_billed.description"The total amount billed by the provider for all services included in this claim. This is the original charge before any discounts, reductions, or insurance adj…changedproperties.amount_billed.extend:type"currency"changedproperties.amount_billed.properties.amount.type["number","null"]changedproperties.amount_billed.properties.iso_4217_currency_code.type["string","null"]changedproperties.amount_billed.required["amount","iso_4217_currency_code"]changedproperties.amount_billed.type"object"changedproperties.benefit_period_end.description"The end date of the benefit period relevant to this EOB or claim. This is the end of the coverage period for deductibles and out-of-pocket calculations."changedproperties.benefit_period_end.extend:type"date"changedproperties.benefit_period_end.type["string","null"]changedproperties.benefit_period_start.description"The start date of the benefit period relevant to this EOB or claim. This is the beginning of the coverage period for deductibles and out-of-pocket calculations…changedproperties.benefit_period_start.extend:type"date"changedproperties.benefit_period_start.type["string","null"]changedproperties.claim_line_items.description"The individual service lines or procedures included in this claim. Each item represents a specific service, procedure, or charge, and includes details about da…changedproperties.claim_line_items.items.additionalPropertiesfalsechangedproperties.claim_line_items.items.properties.amount_allowed.description"The amount allowed by the health plan for this service line after discounts and reductions."changedproperties.claim_line_items.items.properties.amount_allowed.type["number","null"]changedproperties.claim_line_items.items.properties.amount_billed.description"The amount billed by the provider for this specific service line, before any discounts or reductions."changedproperties.claim_line_items.items.properties.amount_billed.type["number","null"]changedproperties.claim_line_items.items.properties.amount_not_covered.description"The amount for this service line that is not covered by the health plan and is the patient's responsibility."changedproperties.claim_line_items.items.properties.amount_not_covered.type["number","null"]changedproperties.claim_line_items.items.properties.coinsurance_amount.description"The coinsurance amount the patient is responsible for on this service line."changedproperties.claim_line_items.items.properties.coinsurance_amount.type["number","null"]changedproperties.claim_line_items.items.properties.copay_amount.description"The copayment amount the patient is responsible for on this service line."changedproperties.claim_line_items.items.properties.copay_amount.type["number","null"]changedproperties.claim_line_items.items.properties.deductible_amount.description"The portion of this service line applied to the patient's deductible."changedproperties.claim_line_items.items.properties.deductible_amount.type["number","null"]changedproperties.claim_line_items.items.properties.discounts_and_reductions.description"The amount of discounts, reductions, or adjustments applied to this service line by the health plan."changedproperties.claim_line_items.items.properties.discounts_and_reductions.type["number","null"]changedproperties.claim_line_items.items.properties.health_plan_responsibility.description"The amount paid or payable by the health plan for this service line."changedproperties.claim_line_items.items.properties.health_plan_responsibility.type["number","null"]changedproperties.claim_line_items.items.properties.notes.description"Any notes, remarks, or explanations related to this service line, such as denial reasons, bundling, or special instructions. May be referenced by footnotes or …changedproperties.claim_line_items.items.properties.notes.type["string","null"]changedproperties.claim_line_items.items.properties.patient_responsibility.description"The total amount the patient is responsible for on this service line, including deductible, copay, coinsurance, and non-covered amounts."changedproperties.claim_line_items.items.properties.patient_responsibility.type["number","null"]changedproperties.claim_line_items.items.properties.service_description.description"A description of the medical service, procedure, or supply provided. May include procedure names, codes, or other identifying information."changedproperties.claim_line_items.items.properties.service_description.type["string","null"]changedproperties.claim_line_items.items.properties.service_end_date.description"The date on which the service or procedure ended, if applicable. May be omitted if service occurred on a single day."changedproperties.claim_line_items.items.properties.service_end_date.extend:type"date"changedproperties.claim_line_items.items.properties.service_end_date.type["string","null"]changedproperties.claim_line_items.items.properties.service_start_date.description"The date on which the service or procedure began or was rendered. May be labeled as 'Service Date', 'Date of Service', or similar."changedproperties.claim_line_items.items.properties.service_start_date.extend:type"date"changedproperties.claim_line_items.items.properties.service_start_date.type["string","null"]changedproperties.claim_line_items.items.required["notes","copay_amount","amount_billed","amount_allowed","service_end_date","deductible_amount","amount_not_covered","coinsurance_amount","service_start_date","…changedproperties.claim_line_items.items.type"object"changedproperties.claim_line_items.type"array"changedproperties.date_processed.description"The date on which this claim or EOB was processed by the health plan. May be labeled as 'Date Processed', 'Processed On', or similar."changedproperties.date_processed.extend:type"date"changedproperties.date_processed.type["string","null"]changedproperties.deductible_maximum.additionalPropertiesfalsechangedproperties.deductible_maximum.description"The total deductible maximum for the benefit period for the patient or family, as specified by the plan."changedproperties.deductible_maximum.extend:type"currency"changedproperties.deductible_maximum.properties.amount.type["number","null"]changedproperties.deductible_maximum.properties.iso_4217_currency_code.type["string","null"]changedproperties.deductible_maximum.required["amount","iso_4217_currency_code"]changedproperties.deductible_maximum.type"object"changedproperties.deductible_met_to_date.additionalPropertiesfalsechangedproperties.deductible_met_to_date.description"The cumulative amount of deductible met by the patient for the current benefit period as of this EOB. This reflects progress toward the annual deductible."changedproperties.deductible_met_to_date.extend:type"currency"changedproperties.deductible_met_to_date.properties.amount.type["number","null"]changedproperties.deductible_met_to_date.properties.iso_4217_currency_code.type["string","null"]changedproperties.deductible_met_to_date.required["amount","iso_4217_currency_code"]changedproperties.deductible_met_to_date.type"object"changedproperties.discounts_and_reductions.additionalPropertiesfalsechangedproperties.discounts_and_reductions.description"The total amount of discounts, reductions, or adjustments applied to the billed charges by the health plan. This may include network discounts, negotiated rate…changedproperties.discounts_and_reductions.extend:type"currency"changedproperties.discounts_and_reductions.properties.amount.type["number","null"]changedproperties.discounts_and_reductions.properties.iso_4217_currency_code.type["string","null"]changedproperties.discounts_and_reductions.required["amount","iso_4217_currency_code"]changedproperties.discounts_and_reductions.type"object"changedproperties.eob_number.description"The unique identifier for this Explanation of Benefits (EOB) document or claim. This is the primary reference number used to track this EOB. May include number…changedproperties.eob_number.type["string","null"]changedproperties.group_number.description"The group or employer number associated with the health plan. This identifies the employer or group plan under which the member is covered. Commonly labeled as…changedproperties.group_number.type["string","null"]changedproperties.health_plan_responsibility.additionalPropertiesfalsechangedproperties.health_plan_responsibility.description"The total amount paid or payable by the health plan for this claim. This is the insurer's share of the allowed amount."changedproperties.health_plan_responsibility.extend:type"currency"changedproperties.health_plan_responsibility.properties.amount.type["number","null"]changedproperties.health_plan_responsibility.properties.iso_4217_currency_code.type["string","null"]changedproperties.health_plan_responsibility.required["amount","iso_4217_currency_code"]changedproperties.health_plan_responsibility.type"object"changedproperties.member_id.description"The unique identification number assigned to the insured member or subscriber. This is used by the health plan to identify the covered individual. May be label…changedproperties.member_id.type["string","null"]changedproperties.out_of_pocket_maximum.additionalPropertiesfalsechangedproperties.out_of_pocket_maximum.description"The total out-of-pocket maximum for the benefit period for the patient or family, as specified by the plan."changedproperties.out_of_pocket_maximum.extend:type"currency"changedproperties.out_of_pocket_maximum.properties.amount.type["number","null"]changedproperties.out_of_pocket_maximum.properties.iso_4217_currency_code.type["string","null"]changedproperties.out_of_pocket_maximum.required["amount","iso_4217_currency_code"]changedproperties.out_of_pocket_maximum.type"object"changedproperties.out_of_pocket_met_to_date.additionalPropertiesfalsechangedproperties.out_of_pocket_met_to_date.description"The cumulative amount of out-of-pocket expenses met by the patient for the current benefit period as of this EOB. This includes deductibles, copays, and coinsu…changedproperties.out_of_pocket_met_to_date.extend:type"currency"changedproperties.out_of_pocket_met_to_date.properties.amount.type["number","null"]changedproperties.out_of_pocket_met_to_date.properties.iso_4217_currency_code.type["string","null"]changedproperties.out_of_pocket_met_to_date.required["amount","iso_4217_currency_code"]changedproperties.out_of_pocket_met_to_date.type"object"changedproperties.patient_name.description"The full name of the individual who received the medical services. May be labeled as 'Patient', 'Covered Person', or similar."changedproperties.patient_name.type["string","null"]changedproperties.patient_responsibility.additionalPropertiesfalsechangedproperties.patient_responsibility.description"The total amount the patient may owe to the provider for these services, after insurance payments and adjustments. This may include deductibles, copays, coinsu…changedproperties.patient_responsibility.extend:type"currency"changedproperties.patient_responsibility.properties.amount.type["number","null"]changedproperties.patient_responsibility.properties.iso_4217_currency_code.type["string","null"]changedproperties.patient_responsibility.required["amount","iso_4217_currency_code"]changedproperties.patient_responsibility.type"object"changedproperties.plan_name.description"The name of the health insurance plan or product under which the claim was processed. May appear as 'Plan Name', 'Product', or similar."changedproperties.plan_name.type["string","null"]changedproperties.provider_name.description"The name of the healthcare provider, facility, or organization that rendered the services for this claim. May be labeled as 'Provider', 'Facility', or similar.…changedproperties.provider_name.type["string","null"]changedproperties.subscriber_name.description"The name of the primary insured individual or policyholder. This is the person who holds the insurance policy, sometimes labeled as 'Subscriber', 'Participant'…changedproperties.subscriber_name.type["string","null"]changedrequired["member_id","plan_name","eob_number","group_number","patient_name","amount_billed","provider_name","amount_allowed","date_processed","subscriber_name","claim_l…changedtype"object"changedbaseProcessor"extraction_performance"You can learn more about Extract configuration in Extend's Extract documentation.
{
"name": "Explanation of Benefits Processing Pipeline",
"steps": [
{
"name": "startTrigger1",
"type": "TRIGGER",
"next": [
{
"step": "parse1"
}
]
},
{
"name": "parse1",
"type": "PARSE",
"config": {
"parseConfig": {
"blockOptions": {
"text": {
"agentic": {
"enabled": true
},
"signatureDetectionEnabled": true
},
"tables": {
"agentic": {
"enabled": true
},
"tableHeaderContinuationEnabled": true
},
"figures": {
"enabled": true
}
},
"chunkingStrategy": {
"type": "page",
"options": {}
}
}
},
"next": [
{
"step": "extraction2"
}
]
},
{
"name": "extraction2",
"type": "EXTRACT",
"config": {
"extractorConfig": {
"schema": {
"type": "object",
"required": [
"member_id",
"plan_name",
"eob_number",
"group_number",
"patient_name",
"amount_billed",
"provider_name",
"amount_allowed",
"date_processed",
"subscriber_name",
"claim_line_items",
"benefit_period_end",
"deductible_maximum",
"benefit_period_start",
"out_of_pocket_maximum",
"deductible_met_to_date",
"patient_responsibility",
"discounts_and_reductions",
"out_of_pocket_met_to_date",
"health_plan_responsibility"
],
"properties": {
"member_id": {
"type": [
"string",
"null"
],
"description": "The unique identification number assigned to the insured member or subscriber. This is used by the health plan to identify the covered individual. May be labeled as 'Member ID', 'Subscriber ID', or similar."
},
"plan_name": {
"type": [
"string",
"null"
],
"description": "The name of the health insurance plan or product under which the claim was processed. May appear as 'Plan Name', 'Product', or similar."
},
"eob_number": {
"type": [
"string",
"null"
],
"description": "The unique identifier for this Explanation of Benefits (EOB) document or claim. This is the primary reference number used to track this EOB. May include numbers, letters, or special characters. Common labels include 'Claim #', 'EOB #', or similar."
},
"group_number": {
"type": [
"string",
"null"
],
"description": "The group or employer number associated with the health plan. This identifies the employer or group plan under which the member is covered. Commonly labeled as 'Group #', 'Group Number', etc."
},
"patient_name": {
"type": [
"string",
"null"
],
"description": "The full name of the individual who received the medical services. May be labeled as 'Patient', 'Covered Person', or similar."
},
"amount_billed": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total amount billed by the provider for all services included in this claim. This is the original charge before any discounts, reductions, or insurance adjustments.",
"extend:type": "currency",
"additionalProperties": false
},
"provider_name": {
"type": [
"string",
"null"
],
"description": "The name of the healthcare provider, facility, or organization that rendered the services for this claim. May be labeled as 'Provider', 'Facility', or similar."
},
"amount_allowed": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total amount allowed by the health plan for the services provided, after discounts and reductions. This is the maximum amount considered for payment.",
"extend:type": "currency",
"additionalProperties": false
},
"date_processed": {
"type": [
"string",
"null"
],
"description": "The date on which this claim or EOB was processed by the health plan. May be labeled as 'Date Processed', 'Processed On', or similar.",
"extend:type": "date"
},
"subscriber_name": {
"type": [
"string",
"null"
],
"description": "The name of the primary insured individual or policyholder. This is the person who holds the insurance policy, sometimes labeled as 'Subscriber', 'Participant', or 'Member'."
},
"claim_line_items": {
"type": "array",
"items": {
"type": "object",
"required": [
"notes",
"copay_amount",
"amount_billed",
"amount_allowed",
"service_end_date",
"deductible_amount",
"amount_not_covered",
"coinsurance_amount",
"service_start_date",
"service_description",
"patient_responsibility",
"discounts_and_reductions",
"health_plan_responsibility"
],
"properties": {
"notes": {
"type": [
"string",
"null"
],
"description": "Any notes, remarks, or explanations related to this service line, such as denial reasons, bundling, or special instructions. May be referenced by footnotes or symbols."
},
"copay_amount": {
"type": [
"number",
"null"
],
"description": "The copayment amount the patient is responsible for on this service line."
},
"amount_billed": {
"type": [
"number",
"null"
],
"description": "The amount billed by the provider for this specific service line, before any discounts or reductions."
},
"amount_allowed": {
"type": [
"number",
"null"
],
"description": "The amount allowed by the health plan for this service line after discounts and reductions."
},
"service_end_date": {
"type": [
"string",
"null"
],
"description": "The date on which the service or procedure ended, if applicable. May be omitted if service occurred on a single day.",
"extend:type": "date"
},
"deductible_amount": {
"type": [
"number",
"null"
],
"description": "The portion of this service line applied to the patient's deductible."
},
"amount_not_covered": {
"type": [
"number",
"null"
],
"description": "The amount for this service line that is not covered by the health plan and is the patient's responsibility."
},
"coinsurance_amount": {
"type": [
"number",
"null"
],
"description": "The coinsurance amount the patient is responsible for on this service line."
},
"service_start_date": {
"type": [
"string",
"null"
],
"description": "The date on which the service or procedure began or was rendered. May be labeled as 'Service Date', 'Date of Service', or similar.",
"extend:type": "date"
},
"service_description": {
"type": [
"string",
"null"
],
"description": "A description of the medical service, procedure, or supply provided. May include procedure names, codes, or other identifying information."
},
"patient_responsibility": {
"type": [
"number",
"null"
],
"description": "The total amount the patient is responsible for on this service line, including deductible, copay, coinsurance, and non-covered amounts."
},
"discounts_and_reductions": {
"type": [
"number",
"null"
],
"description": "The amount of discounts, reductions, or adjustments applied to this service line by the health plan."
},
"health_plan_responsibility": {
"type": [
"number",
"null"
],
"description": "The amount paid or payable by the health plan for this service line."
}
},
"additionalProperties": false
},
"description": "The individual service lines or procedures included in this claim. Each item represents a specific service, procedure, or charge, and includes details about dates, amounts, and benefit application. Format and labeling may vary widely across EOBs."
},
"benefit_period_end": {
"type": [
"string",
"null"
],
"description": "The end date of the benefit period relevant to this EOB or claim. This is the end of the coverage period for deductibles and out-of-pocket calculations.",
"extend:type": "date"
},
"deductible_maximum": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total deductible maximum for the benefit period for the patient or family, as specified by the plan.",
"extend:type": "currency",
"additionalProperties": false
},
"benefit_period_start": {
"type": [
"string",
"null"
],
"description": "The start date of the benefit period relevant to this EOB or claim. This is the beginning of the coverage period for deductibles and out-of-pocket calculations.",
"extend:type": "date"
},
"out_of_pocket_maximum": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total out-of-pocket maximum for the benefit period for the patient or family, as specified by the plan.",
"extend:type": "currency",
"additionalProperties": false
},
"deductible_met_to_date": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The cumulative amount of deductible met by the patient for the current benefit period as of this EOB. This reflects progress toward the annual deductible.",
"extend:type": "currency",
"additionalProperties": false
},
"patient_responsibility": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total amount the patient may owe to the provider for these services, after insurance payments and adjustments. This may include deductibles, copays, coinsurance, and non-covered amounts.",
"extend:type": "currency",
"additionalProperties": false
},
"discounts_and_reductions": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total amount of discounts, reductions, or adjustments applied to the billed charges by the health plan. This may include network discounts, negotiated rates, or other reductions.",
"extend:type": "currency",
"additionalProperties": false
},
"out_of_pocket_met_to_date": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The cumulative amount of out-of-pocket expenses met by the patient for the current benefit period as of this EOB. This includes deductibles, copays, and coinsurance.",
"extend:type": "currency",
"additionalProperties": false
},
"health_plan_responsibility": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total amount paid or payable by the health plan for this claim. This is the insurer's share of the allowed amount.",
"extend:type": "currency",
"additionalProperties": false
}
},
"additionalProperties": false
},
"baseProcessor": "extraction_performance"
}
}
}
]
}# Explanation of Benefits Processing — Extend AI Skill
## What this pipeline does
This pipeline extracts comprehensive structured data from Explanation of Benefits (EOB) documents, capturing member identification, plan details, claim summary, benefit period information, deductible and out-of-pocket tracking, and a complete array of service line items with per-line financial breakdowns. The workflow parses the EOB into enriched markdown, then extracts all 20 required fields and nested line-item objects into a validated JSON structure suitable for downstream claims processing, patient billing, or compliance systems.
## When to use this
- **Insurance claim intake systems**: Automatically capture member, provider, and financial data from incoming EOBs for database ingestion or claims reconciliation.
- **Patient billing portals**: Extract patient responsibility amounts, service descriptions, and deductible/out-of-pocket progress to generate patient-facing statements.
- **Compliance & appeals workflows**: Preserve line-item detail, notes, and denial reasons to support appeal and audit processes.
- **Healthcare cost analytics**: Gather multi-EOB data (billed, allowed, paid, patient-owes) for trend analysis and provider contract validation.
- **High-accuracy scenarios**: When accuracy and reviewability outweigh latency; this config uses `extraction_performance` processor for tables, complex layouts, and footnote handling.
## Processor pipeline
### Step 1: Parse (agentic OCR)
**Processor**: `agentic_ocr` with enhanced block options
**Purpose**: Convert EOB PDF (digital or scanned) into structured markdown chunks, preserving tables, text, and figures.
**Key config**:
- `blockOptions.text.agentic.enabled: true` — enables AI-driven text region detection for complex EOB layouts (multi-column, floating headers, footnotes).
- `blockOptions.text.signatureDetectionEnabled: true` — detects signature blocks (not needed for extraction but useful for routing).
- `blockOptions.tables.agentic.enabled: true` — AI-powered table detection and header continuation (critical for EOBs, which often have multi-page line-item tables).
- `blockOptions.tables.tableHeaderContinuationEnabled: true` — repeats table headers on split pages, preserving column meaning.
- `blockOptions.figures.enabled: true` — extracts embedded charts (rare in EOBs but safe to enable).
- `chunkingStrategy: "page"` — chunks by page, allowing extraction to see full page context for each line item and summary section.
**Why this config**: EOBs have dense tables, repeating headers, and columns labeled inconsistently across carriers. Agentic parsing and table continuation ensure the extractor sees clean, properly-attributed line items even on pages 2–5 of a 10-page EOB.
### Step 2: Extract (structured fields)
**Processor**: `extraction_performance` (not light; accuracy over speed)
**Purpose**: Pull 20 top-level fields (member ID, plan, dates, totals) and an array of service line items, each with 13 sub-fields (copay, deductible, coinsurance, notes, dates, etc.).
**Key config**:
- Schema is `type: "object"` with required array containing all 20 field names.
- Currency fields (`amount_billed`, `amount_allowed`, `patient_responsibility`, etc.) are objects with `{ amount: number|null, iso_4217_currency_code: string|null }`.
- Date fields (`benefit_period_start`, `service_start_date`, etc.) are typed `string|null` with `extend:type: "date"` hint for ISO parsing.
- `claim_line_items` is a required non-nullable array; each item is an object with 13 required fields including amounts, dates, description, and notes.
- `baseProcessor: "extraction_performance"` prioritizes accuracy for complex multi-line tables and conditional logic (e.g., "is this line denied or applied to deductible?").
**Why this config**: EOBs contain financial reconciliation logic (billed ≠ allowed ≠ paid), footnotes tied to specific lines, and per-line deductible/coinsurance splits. `extraction_performance` is tuned for this complexity and will correctly attribute each amount to the right field.
---
## TypeScript implementation
<SDK_CODE>
import { ExtendClient, extendDate, extendCurrency } from "extend-ai";
import { z } from "zod";
import fs from "fs";
const client = new ExtendClient({ token: process.env.EXTEND_API_KEY });
// Define the line item schema for individual service lines.
const LineItemSchema = z.object({
notes: z.string().nullable().describe("Any notes, remarks, or explanations related to this service line, such as denial reasons, bundling, or special instructions. May be referenced by footnotes or symbols."),
copay_amount: z.number().nullable().describe("The copayment amount the patient is responsible for on this service line."),
amount_billed: z.number().nullable().describe("The amount billed by the provider for this specific service line, before any discounts or reductions."),
amount_allowed: z.number().nullable().describe("The amount allowed by the health plan for this service line after discounts and reductions."),
service_end_date: extendDate().describe("The date on which the service or procedure ended, if applicable. May be omitted if service occurred on a single day."),
deductible_amount: z.number().nullable().describe("The portion of this service line applied to the patient's deductible."),
amount_not_covered: z.number().nullable().describe("The amount for this service line that is not covered by the health plan and is the patient's responsibility."),
coinsurance_amount: z.number().nullable().describe("The coinsurance amount the patient is responsible for on this service line."),
service_start_date: extendDate().describe("The date on which the service or procedure began or was rendered. May be labeled as 'Service Date', 'Date of Service', or similar."),
service_description: z.string().nullable().describe("A description of the medical service, procedure, or supply provided. May include procedure names, codes, or other identifying information."),
patient_responsibility: z.number().nullable().describe("The total amount the patient is responsible for on this service line, including deductible, copay, coinsurance, and non-covered amounts."),
discounts_and_reductions: z.number().nullable().describe("The amount of discounts, reductions, or adjustments applied to this service line by the health plan."),
health_plan_responsibility: z.number().nullable().describe("The amount paid or payable by the health plan for this service line."),
});
// Define the main EOB schema with all required fields and nested line items.
const EOBSchema = z.object({
member_id: z.string().nullable().describe("The unique identification number assigned to the insured member or subscriber. This is used by the health plan to identify the covered individual. May be labeled as 'Member ID', 'Subscriber ID', or similar."),
plan_name: z.string().nullable().describe("The name of the health insurance plan or product under which the claim was processed. May appear as 'Plan Name', 'Product', or similar."),
eob_number: z.string().nullable().describe("The unique identifier for this Explanation of Benefits (EOB) document or claim. This is the primary reference number used to track this EOB. May include numbers, letters, or special characters. Common labels include 'Claim #', 'EOB #', or similar."),
group_number: z.string().nullable().describe("The group or employer number associated with the health plan. This identifies the employer or group plan under which the member is covered. Commonly labeled as 'Group #', 'Group Number', etc."),
patient_name: z.string().nullable().describe("The full name of the individual who received the medical services. May be labeled as 'Patient', 'Covered Person', or similar."),
amount_billed: extendCurrency().describe("The total amount billed by the provider for all services included in this claim. This is the original charge before any discounts, reductions, or insurance adjustments."),
provider_name: z.string().nullable().describe("The name of the healthcare provider, facility, or organization that rendered the services for this claim. May be labeled as 'Provider', 'Facility', or similar."),
amount_allowed: extendCurrency().describe("The total amount allowed by the health plan for the services provided, after discounts and reductions. This is the maximum amount considered for payment."),
date_processed: extendDate().describe("The date on which this claim or EOB was processed by the health plan. May be labeled as 'Date Processed', 'Processed On', or similar."),
subscriber_name: z.string().nullable().describe("The name of the primary insured individual or policyholder. This is the person who holds the insurance policy, sometimes labeled as 'Subscriber', 'Participant', or 'Member'."),
claim_line_items: z.array(LineItemSchema).describe("The individual service lines or procedures included in this claim. Each item represents a specific service, procedure, or charge, and includes details about dates, amounts, and benefit application. Format and labeling may vary widely across EOBs."),
benefit_period_end: extendDate().describe("The end date of the benefit period relevant to this EOB or claim. This is the end of the coverage period for deductibles and out-of-pocket calculations."),
deductible_maximum: extendCurrency().describe("The total deductible maximum for the benefit period for the patient or family, as specified by the plan."),
benefit_period_start: extendDate().describe("The start date of the benefit period relevant to this EOB or claim. This is the beginning of the coverage period for deductibles and out-of-pocket calculations."),
out_of_pocket_maximum: extendCurrency().describe("The total out-of-pocket maximum for the benefit period for the patient or family, as specified by the plan."),
deductible_met_to_date: extendCurrency().describe("The cumulative amount of deductible met by the patient for the current benefit period as of this EOB. This reflects progress toward the annual deductible."),
patient_responsibility: extendCurrency().describe("The total amount the patient may owe to the provider for these services, after insurance payments and adjustments. This may include deductibles, copays, coinsurance, and non-covered amounts."),
discounts_and_reductions: extendCurrency().describe("The total amount of discounts, reductions, or adjustments applied to the billed charges by the health plan. This may include network discounts, negotiated rates, or other reductions."),
out_of_pocket_met_to_date: extendCurrency().describe("The cumulative amount of out-of-pocket expenses met by the patient for the current benefit period as of this EOB. This includes deductibles, copays, and coinsurance."),
health_plan_responsibility: extendCurrency().describe("The total amount paid or payable by the health plan for this claim. This is the insurer's share of the allowed amount."),
});
/**
* Main function to process an Explanation of Benefits EOB document.
* Accepts a local file path, converts it to a data URL, and extracts structured fields.
*/
export async function processExplanationofBenefits(filePath: string) {
console.log(`Processing EOB from: ${filePath}`);
// Read the local file and convert to a base64 data URL.
// This allows the Extend SDK to process the file without needing a public URL.
const fileBuffer = fs.readFileSync(filePath);
const base64Data = fileBuffer.toString("base64");
const dataUrl = `data:application/octet-stream;base64,${base64Data}`;
try {
// Step 1: Parse the EOB document into markdown with agentic OCR.
// This enables sophisticated text and table detection for complex EOB layouts.
console.log("Parsing EOB document...");
const parseRun = await client.parseRuns.createAndPoll({
file: { url: dataUrl },
config: {
blockOptions: {
text: {
agentic: { enabled: true },
signatureDetectionEnabled: true,
},
tables: {
agentic: { enabled: true },
tableHeaderContinuationEnabled: true,
},
figures: { enabled: true },
},
chunkingStrategy: {
type: "page",
options: {},
},
},
});
if (parseRun.status !== "PROCESSED") {
throw new Error(`Parse failed with status: ${parseRun.status}`);
}
console.log(`Parse complete. Generated ${parseRun.output.chunks.length} chunks.`);
// Step 2: Extract structured EOB data using the Zod schema.
// Uses extraction_performance processor for high accuracy on complex tables and financial data.
console.log("Extracting structured EOB fields...");
const extractRun = await client.extractRuns.createAndPoll({
file: { url: dataUrl },
config: {
schema: EOBSchema,
},
});
if (extractRun.status !== "PROCESSED") {
throw new Error(`Extraction failed with status: ${extractRun.status}`);
}
const eobData = extractRun.output.value;
// Validate and output the extracted EOB.
console.log("\n=== EXTRACTED EOB DATA ===\n");
console.log(`Member ID: ${eobData.member_id}`);
console.log(`Plan Name: ${eobData.plan_name}`);
console.log(`EOB Number: ${eobData.eob_number}`);
console.log(`Group Number: ${eobData.group_number}`);
console.log(`Patient Name: ${eobData.patient_name}`);
console.log(`Subscriber Name: ${eobData.subscriber_name}`);
console.log(`Provider Name: ${eobData.provider_name}`);
console.log(`Date Processed: ${eobData.date_processed}`);
console.log("\n--- Benefit Period ---");
console.log(`Start: ${eobData.benefit_period_start}`);
console.log(`End: ${eobData.benefit_period_end}`);
console.log("\n--- Financial Summary ---");
console.log(
`Amount Billed: ${eobData.amount_billed.amount} ${eobData.amount_billed.iso_4217_currency_code}`
);
console.log(
`Amount Allowed: ${eobData.amount_allowed.amount} ${eobData.amount_allowed.iso_4217_currency_code}`
);
console.log(
`Discounts & Reductions: ${eobData.discounts_and_reductions.amount} ${eobData.discounts_and_reductions.iso_4217_currency_code}`
);
console.log(
`Health Plan Responsibility: ${eobData.health_plan_responsibility.amount} ${eobData.health_plan_responsibility.iso_4217_currency_code}`
);
console.log(
`Patient Responsibility: ${eobData.patient_responsibility.amount} ${eobData.patient_responsibility.iso_4217_currency_code}`
);
console.log("\n--- Deductible ---");
console.log(
`Maximum: ${eobData.deductible_maximum.amount} ${eobData.deductible_maximum.iso_4217_currency_code}`
);
console.log(
`Met to Date: ${eobData.deductible_met_to_date.amount} ${eobData.deductible_met_to_date.iso_4217_currency_code}`
);
console.log("\n--- Out-of-Pocket ---");
console.log(
`Maximum: ${eobData.out_of_pocket_maximum.amount} ${eobData.out_of_pocket_maximum.iso_4217_currency_code}`
);
console.log(
`Met to Date: ${eobData.out_of_pocket_met_to_date.amount} ${eobData.out_of_pocket_met_to_date.iso_4217_currency_code}`
);
console.log("\n--- Claim Line Items ---");
console.log(`Total Line Items: ${eobData.claim_line_items.length}`);
eobData.claim_line_items.forEach((item, idx) => {
console.log(`\nLine Item ${idx + 1}:`);
console.log(` Service: ${item.service_description}`);
console.log(` Service Date: ${item.service_start_date}import { ExtendClient, extendDate, extendCurrency } from "extend-ai";
import { z } from "zod";
import fs from "fs";
const client = new ExtendClient({ token: process.env.EXTEND_API_KEY });
/**
* Process an Explanation of Benefits (EOB) document.
* Extracts member info, claim details, line items, and benefit period accumulators.
*/
export async function processExplanationOfBenefits(filePath: string) {
// Convert local file to data URL (base64)
const fileBuffer = fs.readFileSync(filePath);
const dataUrl = `data:application/octet-stream;base64,${fileBuffer.toString("base64")}`;
// Define the extraction schema with Zod
const eobSchema = z.object({
// Identifiers
member_id: z.string().nullable().describe(
"The unique identification number assigned to the insured member or subscriber. Used by the health plan to identify the covered individual."
),
eob_number: z.string().nullable().describe(
"The unique identifier for this Explanation of Benefits document. Primary reference number to track this EOB."
),
plan_name: z.string().nullable().describe(
"The name of the health insurance plan or product under which the claim was processed."
),
group_number: z.string().nullable().describe(
"The group or employer number associated with the health plan."
),
// Party information
subscriber_name: z.string().nullable().describe(
"The name of the primary insured individual or policyholder who holds the insurance policy."
),
patient_name: z.string().nullable().describe(
"The full name of the individual who received the medical services."
),
provider_name: z.string().nullable().describe(
"The name of the healthcare provider, facility, or organization that rendered the services."
),
// Claim dates
date_processed: extendDate().describe(
"The date on which this claim or EOB was processed by the health plan. Format: ISO yyyy-mm-dd."
),
benefit_period_start: extendDate().describe(
"The start date of the benefit period relevant to this EOB. Beginning of coverage period for deductibles and out-of-pocket calculations. Format: ISO yyyy-mm-dd."
),
benefit_period_end: extendDate().describe(
"The end date of the benefit period relevant to this EOB. End of coverage period for deductibles and out-of-pocket calculations. Format: ISO yyyy-mm-dd."
),
// Claim-level amounts
amount_billed: extendCurrency().describe(
"The total amount billed by the provider for all services in this claim before any discounts or insurance adjustments."
),
amount_allowed: extendCurrency().describe(
"The total amount allowed by the health plan for the services provided, after discounts and reductions. Maximum amount considered for payment."
),
discounts_and_reductions: extendCurrency().describe(
"The total amount of discounts, reductions, or adjustments applied to billed charges by the health plan. Includes network discounts and negotiated rates."
),
health_plan_responsibility: extendCurrency().describe(
"The total amount paid or payable by the health plan for this claim. The insurer's share of the allowed amount."
),
patient_responsibility: extendCurrency().describe(
"The total amount the patient may owe to the provider for these services, after insurance payments. Includes deductibles, copays, coinsurance, and non-covered amounts."
),
// Benefit period accumulators
deductible_maximum: extendCurrency().describe(
"The total deductible maximum for the benefit period as specified by the plan."
),
deductible_met_to_date: extendCurrency().describe(
"The cumulative amount of deductible met by the patient for the current benefit period as of this EOB. Reflects progress toward annual deductible."
),
out_of_pocket_maximum: extendCurrency().describe(
"The total out-of-pocket maximum for the benefit period as specified by the plan."
),
out_of_pocket_met_to_date: extendCurrency().describe(
"The cumulative amount of out-of-pocket expenses met by the patient for the current benefit period. Includes deductibles, copays, and coinsurance."
),
// Line items (individual services)
claim_line_items: z.array(
z.object({
service_description: z.string().nullable().describe(
"Description of the medical service, procedure, or supply provided. May include procedure names, codes, or other identifying information."
),
service_start_date: extendDate().describe(
"The date on which the service or procedure began or was rendered. Format: ISO yyyy-mm-dd."
),
service_end_date: extendDate().describe(
"The date on which the service or procedure ended, if applicable. May be omitted if service occurred on a single day. Format: ISO yyyy-mm-dd."
),
amount_billed: z.number().nullable().describe(
"The amount billed by the provider for this specific service line, before any discounts or reductions."
),
amount_allowed: z.number().nullable().describe(
"The amount allowed by the health plan for this service line after discounts and reductions."
),
discounts_and_reductions: z.number().nullable().describe(
"The amount of discounts, reductions, or adjustments applied to this service line by the health plan."
),
deductible_amount: z.number().nullable().describe(
"The portion of this service line applied to the patient's deductible."
),
copay_amount: z.number().nullable().describe(
"The copayment amount the patient is responsible for on this service line."
),
coinsurance_amount: z.number().nullable().describe(
"The coinsurance amount the patient is responsible for on this service line."
),
amount_not_covered: z.number().nullable().describe(
"The amount for this service line that is not covered by the health plan and is the patient's responsibility."
),
patient_responsibility: z.number().nullable().describe(
"The total amount the patient is responsible for on this service line, including deductible, copay, coinsurance, and non-covered amounts."
),
health_plan_responsibility: z.number().nullable().describe(
"The amount paid or payable by the health plan for this service line."
),
notes: z.string().nullable().describe(
"Any notes, remarks, or explanations related to this service line, such as denial reasons, bundling, or special instructions."
),
})
).describe(
"The individual service lines or procedures included in this claim. Each item represents a specific service, procedure, or charge with dates, amounts, and benefit application details."
),
});
// Run extraction
console.log(`\n📄 Extracting EOB from: ${filePath}`);
const extractRun = await client.extractRuns.createAndPoll({
file: { url: dataUrl },
config: {
schema: eobSchema,
},
});
// Handle result
if (extractRun.status === "PROCESSED") {
const eobData = extractRun.output.value;
console.log("\n✅ Extraction successful.\n");
console.log("=== EXPLANATION OF BENEFITS SUMMARY ===\n");
// Member & Claim Info
console.log("📋 MEMBER & CLAIM INFO");
console.log(` Member ID: ${eobData.member_id}`);
console.log(` Subscriber: ${eobData.subscriber_name}`);
console.log(` Patient: ${eobData.patient_name}`);
console.log(` Plan: ${eobData.plan_name}`);
console.log(` Group #: ${eobData.group_number}`);
console.log(` EOB #: ${eobData.eob_number}`);
console.log(` Processed: ${eobData.date_processed}\n`);
// Benefit Period
console.log("📅 BENEFIT PERIOD");
console.log(` Start: ${eobData.benefit_period_start}`);
console.log(` End: ${eobData.benefit_period_end}\n`);
// Provider & Service Summary
console.log("🏥 PROVIDER & SERVICE SUMMARY");
console.log(` Provider: ${eobData.provider_name}`);
console.log(` Amount Billed: ${eobData.amount_billed?.amount} ${eobData.amount_billed?.iso_4217_currency_code}`);
console.log(` Amount Allowed: ${eobData.amount_allowed?.amount} ${eobData.amount_allowed?.iso_4217_currency_code}`);
console.log(` Discounts & Reductions: ${eobData.discounts_and_reductions?.amount} ${eobData.discounts_and_reductions?.iso_4217_currency_code}\n`);
// Financial Responsibility
console.log("💰 FINANCIAL RESPONSIBILITY");
console.log(` Plan Pays: ${eobData.health_plan_responsibility?.amount} ${eobData.health_plan_responsibility?.iso_4217_currency_code}`);
console.log(` You Owe: ${eobData.patient_responsibility?.amount} ${eobData.patient_responsibility?.iso_4217_currency_code}\n`);
// Benefit Period Accumulators
console.log("📊 BENEFIT PERIOD ACCUMULATORS");
console.log(` Deductible Maximum: ${eobData.deductible_maximum?.amount} ${eobData.deductible_maximum?.iso_4217_currency_code}`);
console.log(` Deductible Met to Date: ${eobData.deductible_met_to_date?.amount} ${eobData.deductible_met_to_date?.iso_4217_currency_code}`);
console.log(` Out-of-Pocket Maximum: ${eobData.out_of_pocket_maximum?.amount} ${eobData.out_of_pocket_maximum?.iso_4217_currency_code}`);
console.log(` Out-of-Pocket Met to Date: ${eobData.out_of_pocket_met_to_date?.amount} ${eobData.out_of_pocket_met_to_date?.iso_4217_currency_code}\n`);
// Line Items
if (eobData.claim_line_items && eobData.claim_line_items.length > 0) {
console.log("📝 CLAIM LINE ITEMS\n");
eobData.claim_line_items.forEach((item, idx) => {
console.log(` Line ${idx + 1}: ${item.service_description}`);
console.log(` Service Date: ${item.service_start_date}${item.service_end_date ? ` to ${item.service_end_date}` : ""}`);
console.log(` Billed: ${item.amount_billed} | Allowed: ${item.amount_allowed}`);
console.log(` Plan Pays: ${item.health_plan_responsibility} | You Pay: ${item.patient_responsibility}`);
if (item.notes) console.log(` Notes: ${item.notes}`);
console.log();
});
}
return eobData;
} else {
console.error(`❌ Extraction failed with status: ${extractRun.status}`);
throw new Error(`Extraction did not complete successfully: ${extractRun.status}`);
}
}
// Run if invoked directly
processExplanationOfBenefits(process.argv[2] || "./eob.pdf").catch(console.error);import os
import base64
from typing import Any
from extend_ai import Extend
from pydantic import BaseModel, Field
import sys
class ClaimLineItem(BaseModel):
service_description: str | None = Field(
None,
description="Description of the medical service, procedure, or supply provided. May include procedure names, codes, or other identifying information."
)
service_start_date: str = Field(
...,
description="The date on which the service or procedure began or was rendered. Format: ISO yyyy-mm-dd."
)
service_end_date: str = Field(
...,
description="The date on which the service or procedure ended, if applicable. May be omitted if service occurred on a single day. Format: ISO yyyy-mm-dd."
)
amount_billed: float | None = Field(
None,
description="The amount billed by the provider for this specific service line, before any discounts or reductions."
)
amount_allowed: float | None = Field(
None,
description="The amount allowed by the health plan for this service line after discounts and reductions."
)
discounts_and_reductions: float | None = Field(
None,
description="The amount of discounts, reductions, or adjustments applied to this service line by the health plan."
)
deductible_amount: float | None = Field(
None,
description="The portion of this service line applied to the patient's deductible."
)
copay_amount: float | None = Field(
None,
description="The copayment amount the patient is responsible for on this service line."
)
coinsurance_amount: float | None = Field(
None,
description="The coinsurance amount the patient is responsible for on this service line."
)
amount_not_covered: float | None = Field(
None,
description="The amount for this service line that is not covered by the health plan and is the patient's responsibility."
)
patient_responsibility: float | None = Field(
None,
description="The total amount the patient is responsible for on this service line, including deductible, copay, coinsurance, and non-covered amounts."
)
health_plan_responsibility: float | None = Field(
None,
description="The amount paid or payable by the health plan for this service line."
)
notes: str | None = Field(
None,
description="Any notes, remarks, or explanations related to this service line, such as denial reasons, bundling, or special instructions."
)
class ExplanationOfBenefits(BaseModel):
member_id: str | None = Field(
...,
description="The unique identification number assigned to the insured member or subscriber. Used by the health plan to identify the covered individual."
)
eob_number: str | None = Field(
...,
description="The unique identifier for this Explanation of Benefits document. Primary reference number to track this EOB."
)
plan_name: str | None = Field(
...,
description="The name of the health insurance plan or product under which the claim was processed."
)
group_number: str | None = Field(
...,
description="The group or employer number associated with the health plan."
)
subscriber_name: str | None = Field(
...,
description="The name of the primary insured individual or policyholder who holds the insurance policy."
)
patient_name: str | None = Field(
...,
description="The full name of the individual who received the medical services."
)
provider_name: str | None = Field(
...,
description="The name of the healthcare provider, facility, or organization that rendered the services."
)
date_processed: str = Field(
...,
description="The date on which this claim or EOB was processed by the health plan. Format: ISO yyyy-mm-dd."
)
benefit_period_start: str = Field(
...,
description="The start date of the benefit period relevant to this EOB. Beginning of coverage period for deductibles and out-of-pocket calculations. Format: ISO yyyy-mm-dd."
)
benefit_period_end: str = Field(
...,
description="The end date of the benefit period relevant to this EOB. End of coverage period for deductibles and out-of-pocket calculations. Format: ISO yyyy-mm-dd."
)
amount_billed: dict[str, Any] = Field(
...,
description="The total amount billed by the provider for all services in this claim before any discounts or insurance adjustments."
)
amount_allowed: dict[str, Any] = Field(
...,
description="The total amount allowed by the health plan for the services provided, after discounts and reductions. Maximum amount considered for payment."
)
discounts_and_reductions: dict[str, Any] = Field(
...,
description="The total amount of discounts, reductions, or adjustments applied to billed charges by the health plan. Includes network discounts and negotiated rates."
)
health_plan_responsibility: dict[str, Any] = Field(
...,
description="The total amount paid or payable by the health plan for this claim. The insurer's share of the allowed amount."
)
patient_responsibility: dict[str, Any] = Field(
...,
description="The total amount the patient may owe to the provider for these services, after insurance payments. Includes deductibles, copays, coinsurance, and non-covered amounts."
)
deductible_maximum: dict[str, Any] = Field(
...,
description="The total deductible maximum for the benefit period as specified by the plan."
)
deductible_met_to_date: dict[str, Any] = Field(
...,
description="The cumulative amount of deductible met by the patient for the current benefit period as of this EOB. Reflects progress toward annual deductible."
)
out_of_pocket_maximum: dict[str, Any] = Field(
...,
description="The total out-of-pocket maximum for the benefit period as specified by the plan."
)
out_of_pocket_met_to_date: dict[str, Any] = Field(
...,
description="The cumulative amount of out-of-pocket expenses met by the patient for the current benefit period. Includes deductibles, copays, and coinsurance."
)
claim_line_items: list[ClaimLineItem] = Field(
...,
description="The individual service lines or procedures included in this claim. Each item represents a specific service, procedure, or charge with dates, amounts, and benefit application details."
)
def process_explanation_of_benefits(file_path: str) -> ExplanationOfBenefits:
"""
Process an Explanation of Benefits (EOB) document.
Extracts member info, claim details, line items, and benefit period accumulators.
"""
client = Extend(token=os.environ["EXTEND_API_KEY"])
with open(file_path, "rb") as f:
file_buffer = f.read()
data_url = f"data:application/octet-stream;base64,{base64.b64encode(file_buffer).decode('utf-8')}"
eob_schema = {
"type": "object",
"properties": {
"member_id": {
"type": ["string", "null"],
"description": "The unique identification number assigned to the insured member or subscriber. Used by the health plan to identify the covered individual."
},
"eob_number": {
"type": ["string", "null"],
"description": "The unique identifier for this Explanation of Benefits document. Primary reference number to track this EOB."
},
"plan_name": {
"type": ["string", "null"],
"description": "The name of the health insurance plan or product under which the claim was processed."
},
"group_number": {
"type": ["string", "null"],
"description": "The group or employer number associated with the health plan."
},
"subscriber_name": {
"type": ["string", "null"],
"description": "The name of the primary insured individual or policyholder who holds the insurance policy."
},
"patient_name": {
"type": ["string", "null"],
"description": "The full name of the individual who received the medical services."
},
"provider_name": {
"type": ["string", "null"],
"description": "The name of the healthcare provider, facility, or organization that rendered the services."
},
"date_processed": {
"type": ["string", "null"],
"description": "The date on which this claim or EOB was processed by the health plan. Format: ISO yyyy-mm-dd.",
"extend:type": "date"
},
"benefit_period_start": {
"type": ["string", "null"],
"description": "The start date of the benefit period relevant to this EOB. Beginning of coverage period for deductibles and out-of-pocket calculations. Format: ISO yyyy-mm-dd.",
"extend:type": "date"
},
"benefit_period_end": {
"type": ["string", "null"],
"description": "The end date of the benefit period relevant to this EOB. End of coverage period for deductibles and out-of-pocket calculations. Format: ISO yyyy-mm-dd.",
"extend:type": "date"
},
"amount_billed": {
"type": "object",
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]}
},
"description": "The total amount billed by the provider for all services in this claim before any discounts or insurance adjustments.",
"extend:type": "currency"
},
"amount_allowed": {
"type": "object",
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]}
},
"description": "The total amount allowed by the health plan for the services provided, after discounts and reductions. Maximum amount considered for payment.",
"extend:type": "currency"
},
"discounts_and_reductions": {
"type": "object",
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]}
},
"description": "The total amount of discounts, reductions, or adjustments applied to billed charges by the health plan. Includes network discounts and negotiated rates.",
"extend:type": "currency"
},
"health_plan_responsibility": {
"type": "object",
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]}
},
"description": "The total amount paid or payable by the health plan for this claim. The insurer's share of the allowed amount.",
"extend:type": "currency"
},
"patient_responsibility": {
"type": "object",
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]}
},
"description": "The total amount the patient may owe to the provider for these services, after insurance payments. Includes deductibles, copays, coinsurance, and non-covered amounts.",
"extend:type": "currency"
},
"deductible_maximum": {
"type": "object",
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]}
},
"description": "The total deductible maximum for the benefit period as specified by the plan.",
"extend:type": "currency"
},
"deductible_met_to_date": {
"type": "object",
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]}
},
"description": "The cumulative amount of deductible met by the patient for the current benefit period as of this EOB. Reflects progress toward annual deductible.",
"extend:type": "currency"
},
"out_of_pocket_maximum": {
"type": "object",
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]}
},
"description": "The total out-of-pocket maximum for the benefit period as specified by the plan.",
"extend:type": "currency"
},
"out_of_pocket_met_to_date": {
"type": "object",
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]}
},
"description": "The cumulative amount of out-of-pocket expenses met by the patient for the current benefit period. Includes deductibles, copays, and coinsurance.",
"extend:type": "currency"
},
"claim_line_items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"service_description": {
"type": ["string", "null"],
"description": "Description of the medical service, procedure, or supply provided. May include procedure names, codes, or other identifying information."
},
"service_start_date": {
"type": ["string", "null"],
"description": "The date on which the service or procedure began or was rendered. Format: ISO yyyy-mm-dd.",
"extend:type": "date"
},
"service_end_date": {
"type": ["string", "null"],
"description": "The date on which the service or procedure ended, if applicable. May be omitted if service occurred on a single day. Format: ISO yyyy-mm-dd.",
"extend:type": "date"
},
"amount_billed": {
"type": ["number", "null"],
"description": "The amount billed by the provider for this specific service line, before any discounts or reductions."
},
"amount_allowed": {
"type": ["number", "null"],
"description": "The amount allowed by the health plan for this service line after discounts and reductions."
},
"discounts_and_reductions": {
"type": ["number", "null"],
"description": "The amount of discounts, reductions, or adjustments applied to this service line by the health plan."
},
"deductible_amount": {
"type": ["number", "null"],
"description": "The portion of this service line applied to the patient's deductible."
},
"copay_amount": {
"type": ["number", "null"],
"description": "The copayment amount the patient is responsible for on this service line."
},
"coinsurance_amount": {
"type": ["number", "null"],
"description": "The coinsurance amount the patient is responsible for on this service line."
},
"amount_not_covered": {
"type": ["number", "null"],
"description": "The amount for this service line that is not covered by the health plan and is the patient's responsibility."
},
"patient_responsibility": {
"type": ["number", "null"],
"description": "The total amount the patient is responsible for on this service line, including deductible, copay, coinsurance, and non-covered amounts."
},
"health_plan_responsibility": {
"type": ["number", "null"],
"description": "The amount paid or payable by the health plan for this service line."
},
"notes": {
"type": ["string", "null"],
"description": "Any notes, remarks, or explanations related to this service line, such as denial reasons, bundling, or special instructions."
}
}
},
"description": "The individual service lines or procedures included in this claim. Each item represents a specific service, procedure, or charge with dates, amounts, and benefit application details."
}
},
"required": [
"member_id",
"eob_number",
"plan_name",
"group_number",
"subscriber_name",
"patient_name",
"provider_name",
"date_processed",
"benefit_period_start",
"benefit_period_end",
"amount_billed",
"amount_allowed",
"discounts_and_reductions",
"health_plan_responsibility",
"patient_responsibility",
"deductible_maximum",
"deductible_met_to_date",
"out_of_pocket_maximum",
"out_of_pocket_met_to_date",
"claim_line_items"
]
}
print(f"\n📄 Extracting EOB from: {file_path}")
extract_run = client.extract_runs.create_and_poll(
file={"url": data_url},
config={
"schema": eob_schema,
},
)
if extract_run.status == "PROCESSED":
eob_data = extract_run.output.value
print("\n✅ Extraction successful.\n")
print("=== EXPLANATION OF BENEFITS SUMMARY ===\n")
print("📋 MEMBER & CLAIM INFO")
print(f" Member ID: {eob_data['member_id']}")
print(f" Subscriber: {eob_data['subscriber_name']}")
print(f" Patient: {eob_data['patient_name']}")
print(f" Plan: {eob_data['plan_name']}")
print(f" Group #: {eob_data['group_number']}")
print(f" EOB #: {eob_data['eob_number']}")
print(f" Processed: {eob_data['date_processed']}\n")
print("📅 BENEFIT PERIOD")
print(f" Start: {eob_data['benefit_period_start']}")
print(f" End: {eob_data['benefit_period_end']}\n")
print("🏥 PROVIDER & SERVICE SUMMARY")
print(f" Provider: {eob_data['provider_name']}")
amount_billed = eob_data['amount_billed']
print(f" Amount Billed: {amount_billed['amount']} {amount_billed['iso_4217_currency_code']}")
amount_allowed = eob_data['amount_allowed']
print(f" Amount Allowed: {amount_allowed['amount']} {amount_allowed['iso_4217_currency_code']}")
discounts = eob_data['discounts_and_reductions']
print(f" Discounts & Reductions: {discounts['amount']} {discounts['iso_4217_currency_code']}\n")
print("💰 FINANCIAL RESPONSIBILITY")
plan_resp = eob_data['health_plan_responsibility']
print(f" Plan Pays: {plan_resp['amount']} {plan_resp['iso_4217_currency_code']}")
patient_resp = eob_data['patient_responsibility']
print(f" You Owe: {patient_resp['amount']} {patient_resp['iso_4217_currency_code']}\n")
print("📊 BENEFIT PERIOD ACCUMULATORS")
ded_max = eob_data['deductible_maximum']
print(f" Deductible Maximum: {ded_max['amount']} {ded_max['iso_4217_currency_code']}")
ded_met = eob_data['deductible_met_to_date']
print(f" Deductible Met to Date: {ded_met['amount']} {ded_met['iso_4217_currency_code']}")
oop_max = eob_data['out_of_pocket_maximum']
print(f" Out-of-Pocket Maximum: {oop_max['amount']} {oop_max['iso_4217_currency_code']}")
oop_met = eob_data['out_of_pocket_met_to_date']
print(f" Out-of-Pocket Met to Date: {oop_met['amount']} {oop_met['iso_4217_currency_code']}\n")
if eob_data['claim_line_items'] and len(eob_data['claim_line_items']) > 0:
print("📝 CLAIM LINE ITEMS\n")
for idx, item in enumerate(eob_data['claim_line_items']):
print(f" Line {idx + 1}: {item['service_description']}")
service_dates = f"{item['service_start_date']}"
if item['service_end_date']:
service_dates += f" to {item['service_end_date']}"
print(f" Service Date: {service_dates}")
print(f" Billed: {item['amount_billed']} | Allowed: {item['amount_allowed']}")
print(f" Plan Pays: {item['health_plan_responsibility']} | You Pay: {item['patient_responsibility']}")
if item['notes']:
print(f" Notes: {item['notes']}")
print()
return eob_data
else:
print(f"❌ Extraction failed with status: {extract_run.status}")
raise Exception(f"Extraction did not complete successfully: {extract_run.status}")
if __name__ == "__main__":
file_to_process = sys.argv[1] if len(sys.argv) > 1 else "./eob.pdf"
process_explanation_of_benefits(file_to_process)/*
* Extend AI Java example: REST API directly (no official SDK yet).
* Uses java.net.http.HttpClient and java.lang built-ins only.
*/
import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.List;
import java.util.Map;
public class ExplanationOfBenefitsExtractor {
private static final String API_BASE_URL = "https://api.extend.ai";
private static final String API_KEY = System.getenv("EXTEND_API_KEY");
private static final HttpClient httpClient = HttpClient.newHttpClient();
/**
* Process an Explanation of Benefits (EOB) document.
* Extracts member info, claim details, line items, and benefit period accumulators.
*/
public static Map<String, Object> processExplanationOfBenefits(String filePath)
throws IOException, InterruptedException {
// Read file and convert to data URL (base64)
byte[] fileBuffer = Files.readAllBytes(Paths.get(filePath));
String base64Data = Base64.getEncoder().encodeToString(fileBuffer);
String dataUrl = "data:application/octet-stream;base64," + base64Data;
// Define the extraction schema as JSON
String schemaJson =
"{\n"
+ " \"type\": \"object\",\n"
+ " \"properties\": {\n"
+ " \"member_id\": { \"type\": [\"string\", \"null\"] },\n"
+ " \"eob_number\": { \"type\": [\"string\", \"null\"] },\n"
+ " \"plan_name\": { \"type\": [\"string\", \"null\"] },\n"
+ " \"group_number\": { \"type\": [\"string\", \"null\"] },\n"
+ " \"subscriber_name\": { \"type\": [\"string\", \"null\"] },\n"
+ " \"patient_name\": { \"type\": [\"string\", \"null\"] },\n"
+ " \"provider_name\": { \"type\": [\"string\", \"null\"] },\n"
+ " \"date_processed\": { \"type\": [\"string\", \"null\"], \"extend:type\": \"date\" },\n"
+ " \"benefit_period_start\": { \"type\": [\"string\", \"null\"], \"extend:type\": \"date\" },\n"
+ " \"benefit_period_end\": { \"type\": [\"string\", \"null\"], \"extend:type\": \"date\" },\n"
+ " \"amount_billed\": {\n"
+ " \"type\": \"object\",\n"
+ " \"properties\": {\n"
+ " \"amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"iso_4217_currency_code\": { \"type\": [\"string\", \"null\"] }\n"
+ " },\n"
+ " \"extend:type\": \"currency\"\n"
+ " },\n"
+ " \"amount_allowed\": {\n"
+ " \"type\": \"object\",\n"
+ " \"properties\": {\n"
+ " \"amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"iso_4217_currency_code\": { \"type\": [\"string\", \"null\"] }\n"
+ " },\n"
+ " \"extend:type\": \"currency\"\n"
+ " },\n"
+ " \"discounts_and_reductions\": {\n"
+ " \"type\": \"object\",\n"
+ " \"properties\": {\n"
+ " \"amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"iso_4217_currency_code\": { \"type\": [\"string\", \"null\"] }\n"
+ " },\n"
+ " \"extend:type\": \"currency\"\n"
+ " },\n"
+ " \"health_plan_responsibility\": {\n"
+ " \"type\": \"object\",\n"
+ " \"properties\": {\n"
+ " \"amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"iso_4217_currency_code\": { \"type\": [\"string\", \"null\"] }\n"
+ " },\n"
+ " \"extend:type\": \"currency\"\n"
+ " },\n"
+ " \"patient_responsibility\": {\n"
+ " \"type\": \"object\",\n"
+ " \"properties\": {\n"
+ " \"amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"iso_4217_currency_code\": { \"type\": [\"string\", \"null\"] }\n"
+ " },\n"
+ " \"extend:type\": \"currency\"\n"
+ " },\n"
+ " \"deductible_maximum\": {\n"
+ " \"type\": \"object\",\n"
+ " \"properties\": {\n"
+ " \"amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"iso_4217_currency_code\": { \"type\": [\"string\", \"null\"] }\n"
+ " },\n"
+ " \"extend:type\": \"currency\"\n"
+ " },\n"
+ " \"deductible_met_to_date\": {\n"
+ " \"type\": \"object\",\n"
+ " \"properties\": {\n"
+ " \"amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"iso_4217_currency_code\": { \"type\": [\"string\", \"null\"] }\n"
+ " },\n"
+ " \"extend:type\": \"currency\"\n"
+ " },\n"
+ " \"out_of_pocket_maximum\": {\n"
+ " \"type\": \"object\",\n"
+ " \"properties\": {\n"
+ " \"amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"iso_4217_currency_code\": { \"type\": [\"string\", \"null\"] }\n"
+ " },\n"
+ " \"extend:type\": \"currency\"\n"
+ " },\n"
+ " \"out_of_pocket_met_to_date\": {\n"
+ " \"type\": \"object\",\n"
+ " \"properties\": {\n"
+ " \"amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"iso_4217_currency_code\": { \"type\": [\"string\", \"null\"] }\n"
+ " },\n"
+ " \"extend:type\": \"currency\"\n"
+ " },\n"
+ " \"claim_line_items\": {\n"
+ " \"type\": \"array\",\n"
+ " \"items\": {\n"
+ " \"type\": \"object\",\n"
+ " \"properties\": {\n"
+ " \"service_description\": { \"type\": [\"string\", \"null\"] },\n"
+ " \"service_start_date\": { \"type\": [\"string\", \"null\"], \"extend:type\": \"date\" },\n"
+ " \"service_end_date\": { \"type\": [\"string\", \"null\"], \"extend:type\": \"date\" },\n"
+ " \"amount_billed\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"amount_allowed\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"discounts_and_reductions\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"deductible_amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"copay_amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"coinsurance_amount\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"amount_not_covered\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"patient_responsibility\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"health_plan_responsibility\": { \"type\": [\"number\", \"null\"] },\n"
+ " \"notes\": { \"type\": [\"string\", \"null\"] }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ " }\n"
+ "}\n";
// Build request body
String requestBodyJson =
"{\n"
+ " \"file\": { \"url\": \""
+ escapeJson(dataUrl)
+ "\" },\n"
+ " \"config\": { \"schema\": "
+ schemaJson
+ " }\n"
+ "}\n";
System.out.println("\n📄 Extracting EOB from: " + filePath);
// Create extract run
String extractRunId = createExtractRun(requestBodyJson);
System.out.println(" Extract run ID: " + extractRunId);
// Poll for completion
Map<String, Object> extractRun = pollExtractRun(extractRunId);
// Handle result
String status = (String) extractRun.get("status");
if ("PROCESSED".equals(status)) {
Map<String, Object> output = (Map<String, Object>) extractRun.get("output");
Map<String, Object> eobData = (Map<String, Object>) output.get("value");
System.out.println("\n✅ Extraction successful.\n");
System.out.println("=== EXPLANATION OF BENEFITS SUMMARY ===\n");
// Member & Claim Info
System.out.println("📋 MEMBER & CLAIM INFO");
System.out.println(" Member ID: " + eobData.get("member_id"));
System.out.println(" Subscriber: " + eobData.get("subscriber_name"));
System.out.println(" Patient: " + eobData.get("patient_name"));
System.out.println(" Plan: " + eobData.get("plan_name"));
System.out.println(" Group #: " + eobData.get("group_number"));
System.out.println(" EOB #: " + eobData.get("eob_number"));
System.out.println(" Processed: " + eobData.get("date_processed") + "\n");
// Benefit Period
System.out.println("📅 BENEFIT PERIOD");
System.out.println(" Start: " + eobData.get("benefit_period_start"));
System.out.println(" End: " + eobData.get("benefit_period_end") + "\n");
// Provider & Service Summary
System.out.println("🏥 PROVIDER & SERVICE SUMMARY");
System.out.println(" Provider: " + eobData.get("provider_name"));
printCurrencyField(eobData, "amount_billed", " Amount Billed: ");
printCurrencyField(eobData, "amount_allowed", " Amount Allowed: ");
printCurrencyField(eobData, "discounts_and_reductions", " Discounts & Reductions: ");
System.out.println();
// Financial Responsibility
System.out.println("💰 FINANCIAL RESPONSIBILITY");
printCurrencyField(eobData, "health_plan_responsibility", " Plan Pays: ");
printCurrencyField(eobData, "patient_responsibility", " You Owe: ");
System.out.println();
// Benefit Period Accumulators
System.out.println("📊 BENEFIT PERIOD ACCUMULATORS");
printCurrencyField(eobData, "deductible_maximum", " Deductible Maximum: ");
printCurrencyField(eobData, "deductible_met_to_date", " Deductible Met to Date: ");
printCurrencyField(eobData, "out_of_pocket_maximum", " Out-of-Pocket Maximum: ");
printCurrencyField(
eobData, "out_of_pocket_met_to_date", " Out-of-Pocket Met to Date: ");
System.out.println();
// Line Items
List<Map<String, Object>> lineItems =
(List<Map<String, Object>>) eobData.get("claim_line_items");
if (lineItems != null && !lineItems.isEmpty()) {
System.out.println("📝 CLAIM LINE ITEMS\n");
for (int idx = 0; idx < lineItems.size(); idx++) {
Map<String, Object> item = lineItems.get(idx);
System.out.println(" Line " + (idx + 1) + ": " + item.get("service_description"));
String endDate = (String) item.get("service_end_date");
String dateRange =
endDate != null && !endDate.isEmpty()
? " to " + endDate
: "";
System.out.println(" Service Date: " + item.get("service_start_date") + dateRange);
System.out.println(
" Billed: "
+ item.get("amount_billed")
+ " | Allowed: "
+ item.get("amount_allowed"));
System.out.println(
" Plan Pays: "
+ item.get("health_plan_responsibility")
+ " | You Pay: "
+ item.get("patient_responsibility"));
String notes = (String) item.get("notes");
if (notes != null && !notes.isEmpty()) {
System.out.println(" Notes: " + notes);
}
System.out.println();
}
}
return eobData;
} else {
System.err.println("❌ Extraction failed with status: " + status);
throw new RuntimeException("Extraction did not complete successfully: " + status);
}
}
private static String createExtractRun(String requestBody)
throws IOException, InterruptedException {
HttpRequest request =
HttpRequest.newBuilder()
.uri(URI.create(API_BASE_URL + "/extraction/runs"))
.header("Authorization", "Bearer " + API_KEY)
.header("Content-Type", "application/json")
.POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200 && response.statusCode() != 201) {
throw new RuntimeException(
"Failed to create extract run. Status: "
+ response.statusCode()
+ ", Body: "
+ response.body());
}
// Parse JSON response to extract ID
String responseBody = response.body();
int idIndex = responseBody.indexOf("\"id\"");
if (idIndex != -1) {
int quoteStart = responseBody.indexOf("\"", idIndex + 5);
int quoteEnd = responseBody.indexOf("\"", quoteStart + 1);
return responseBody.substring(quoteStart + 1, quoteEnd);
}
throw new RuntimeException("Could not parse extract run ID from response");
}
private static Map<String, Object> pollExtractRun(String runId)
throws IOException, InterruptedException {
int maxAttempts = 120;
int attemptCount = 0;
while (attemptCount < maxAttempts) {
HttpRequest request =
HttpRequest.newBuilder()
.uri(URI.create(API_BASE_URL + "/extraction/runs/" + runId))
.header("Authorization", "Bearer " + API_KEY)
.GET()
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
if (response.statusCode() != 200) {
throw new RuntimeException(
"Failed to poll extract run. Status: "
+ response.statusCode()
+ ", Body: "
+ response.body());
}
String responseBody = response.body();
Map<String, Object> result = parseJsonResponse(responseBody);
String status = (String) result.get("status");
if ("PROCESSED".equals(status) || "FAILED".equals(status)) {
return result;
}
attemptCount++;
if (attemptCount < maxAttempts) {
Thread.sleep(1000); // Wait 1 second before next poll
}
}
throw new RuntimeException("Extract run polling timed out after " + maxAttempts + " attempts");
}
private static Map<String, Object> parseJsonResponse(String json) {
// Simple JSON parsing for extract run response
Map<String, Object> result = new java.util.HashMap<>();
// Extract status
int statusIndex = json.indexOf("\"status\"");
if (statusIndex != -1) {
int quoteStart = json.indexOf("\"", statusIndex + 10);
int quoteEnd = json.indexOf("\"", quoteStart + 1);
result.put("status", json.substring(quoteStart + 1, quoteEnd));
}
// Extract output if present
int outputIndex = json.indexOf("\"output\"");
if (outputIndex != -1) {
int valueIndex = json.indexOf("\"value\"", outputIndex);
if (valueIndex != -1) {
// Extract the value object (simplified: assumes it's a valid JSON object)
int openBrace = json.indexOf("{", valueIndex);
int closeBrace = findMatchingBrace(json, openBrace);
String valueJson = json.substring(openBrace, closeBrace + 1);
Map<String, Object> output = new java.util.HashMap<>();
output.put("value", parseComplexJson(valueJson));
result.put("output", output);
}
}
return result;
}
private static Map<String, Object> parseComplexJson(String json) {
// Simplified JSON object parser for EOB data
Map<String, Object> map = new java.util.HashMap<>();
int pos = 0;
while (pos < json.length()) {
// Find next key
int keyStart = json.indexOf("\"", pos);
if (keyStart == -1) break;
int keyEnd = json.indexOf("\"", keyStart + 1);
String key = json.substring(keyStart + 1, keyEnd);
// Find colon
int colonPos = json.indexOf(":", keyEnd);
if (colonPos == -1) break;
// Parse value
int valueStart = colonPos + 1;
while (valueStart < json.length() && Character.isWhitespace(json.charAt(valueStart))) {
valueStart++;
}
Object value = null;
if (json.charAt(valueStart) == '"') {
// String value
int stringEnd = json.indexOf("\"", valueStart + 1);
value = json.substring(valueStart + 1, stringEnd);
pos = stringEnd + 1;
} else if (json.charAt(valueStart) == '{') {
// Object value
int objectEnd = findMatchingBrace(json, valueStart);
value = parseComplexJson(json.substring(valueStart, objectEnd + 1));
pos = objectEnd + 1;
} else if (json.charAt(valueStart) == '[') {
// Array value
int arrayEnd = findMatchingBracket(json, valueStart);
value = parseJsonArray(json.substring(valueStart, arrayEnd + 1));
pos = arrayEnd + 1;
} else if (json.startsWith("null", valueStart)) {
value = null;
pos = valueStart + 4;
} else {
// Number or boolean
int endPos = valueStart;
while (endPos < json.length()
&& !Character.isWhitespace(json.charAt(endPos))
&& json.charAt(endPos) != ','
&& json.charAt(endPos) != '}') {
endPos++;
}
String numStr = json.substring(valueStart, endPos).trim();
try {
if (numStr.contains(".")) {
value = Double.parseDouble(numStr);
} else {
value = Long.parseLong(numStr);
}
} catch (NumberFormatException e) {
value = numStr;
}
pos = endPos;
}
map.put(key, value);
// Skip to next comma or end
while (pos < json.length() && json.charAt(pos) != ',' && json.charAt(pos) != '}') {
pos++;
}
if (pos < json.length() && json.charAt(pos) == ',') {
pos++;
}
}
return map;
}
private static List<Map<String, Object>> parseJsonArray(String json) {
List<Map<String, Object>> list = new java.util.ArrayList<>();
int pos = 1; // Skip opening bracket
while (pos < json.length() && json.charAt(pos) != ']') {
while (pos < json.length() && Character.isWhitespace(json.charAt(pos))) {
pos++;
}
if (json.charAt(pos) == '{') {
int end = findMatchingBrace(json, pos);
list.add(parseComplexJson(json.substring(pos, end + 1)));
pos = end + 1;
}
while (pos < json.length() && json.charAt(pos) != ',' && json.charAt(pos) != ']') {
pos++;
}
if (pos < json.length() && json.charAt(pos) == ',') {
pos++;
}
}
return list;
}
private static int findMatchingBrace(String str, int start) {
int count = 1;
int pos = start + 1;
while (pos < str.length() && count > 0) {
if (str.charAt(pos) == '{') count++;
else if (str.charAt(pos) == '}') count--;
pos++;
}
return pos - 1;
}
private static int findMatchingBracket(String str, int start) {
int count = 1;
int pos = start + 1;
while (pos < str.length() && count > 0) {
if (str.charAt(pos) == '[') count++;
else if (str.charAt(pos) == ']') count--;
pos++;
}
return pos - 1;
}
private static void printCurrencyField(
Map<String, Object> data, String fieldName, String label) {
Object fieldValue = data.get(fieldName);
if (fieldValue instanceof Map) {
Map<String, Object> currencyObj = (Map<String, Object>) fieldValue;
Object amount = currencyObj.get("amount");
Object currency = currencyObj.get("iso_4217_currency_code");
System.out.println(label + amount + " " + currency);
} else {
System.out.println(label + fieldValue);
}
}
private static String escapeJson(String str) {
return str.replace("\\", "\\\\")
.replace("\"", "\\\"")
.replace("\n", "\\n")
.replace("\r", "\\r")
.replace("\t", "\\t");
}
public static void main(String[] args) {
try {
String filePath = args.length > 0 ? args[0] : "./eob.pdf";
processExplanationOfBenefits(filePath);
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
e.printStackTrace();
}
}
}package main
import (
"bytes"
"encoding/base64"
"encoding/json"
"fmt"
"io"
"net/http"
"os"
"time"
)
// NOTE: This code uses the Extend REST API directly because Extend has no official Go SDK.
// The API endpoints and request/response formats match those used by the TypeScript SDK.
type CurrencyValue struct {
Amount *float64 `json:"amount"`
ISO4217CurrencyCode *string `json:"iso_4217_currency_code"`
}
type ClaimLineItem struct {
ServiceDescription *string `json:"service_description"`
ServiceStartDate *string `json:"service_start_date"`
ServiceEndDate *string `json:"service_end_date"`
AmountBilled *float64 `json:"amount_billed"`
AmountAllowed *float64 `json:"amount_allowed"`
DiscountsAndReductions *float64 `json:"discounts_and_reductions"`
DeductibleAmount *float64 `json:"deductible_amount"`
CopayAmount *float64 `json:"copay_amount"`
CoinsuranceAmount *float64 `json:"coinsurance_amount"`
AmountNotCovered *float64 `json:"amount_not_covered"`
PatientResponsibility *float64 `json:"patient_responsibility"`
HealthPlanResponsibility *float64 `json:"health_plan_responsibility"`
Notes *string `json:"notes"`
}
type ExplanationOfBenefits struct {
MemberID *string `json:"member_id"`
EOBNumber *string `json:"eob_number"`
PlanName *string `json:"plan_name"`
GroupNumber *string `json:"group_number"`
SubscriberName *string `json:"subscriber_name"`
PatientName *string `json:"patient_name"`
ProviderName *string `json:"provider_name"`
DateProcessed *string `json:"date_processed"`
BenefitPeriodStart *string `json:"benefit_period_start"`
BenefitPeriodEnd *string `json:"benefit_period_end"`
AmountBilled *CurrencyValue `json:"amount_billed"`
AmountAllowed *CurrencyValue `json:"amount_allowed"`
DiscountsAndReductions *CurrencyValue `json:"discounts_and_reductions"`
HealthPlanResponsibility *CurrencyValue `json:"health_plan_responsibility"`
PatientResponsibility *CurrencyValue `json:"patient_responsibility"`
DeductibleMaximum *CurrencyValue `json:"deductible_maximum"`
DeductibleMetToDate *CurrencyValue `json:"deductible_met_to_date"`
OutOfPocketMaximum *CurrencyValue `json:"out_of_pocket_maximum"`
OutOfPocketMetToDate *CurrencyValue `json:"out_of_pocket_met_to_date"`
ClaimLineItems []ClaimLineItem `json:"claim_line_items"`
}
type ExtractSchema struct {
Type string `json:"type"`
Properties map[string]interface{} `json:"properties"`
Required []string `json:"required"`
}
type ExtractRunRequest struct {
File FileInput `json:"file"`
Config ExtractConfig `json:"config"`
}
type FileInput struct {
URL string `json:"url"`
}
type ExtractConfig struct {
Schema ExtractSchema `json:"schema"`
}
type ExtractRunResponse struct {
ID string `json:"id"`
Status string `json:"status"`
Output *OutputValue `json:"output"`
Error *ErrorDetails `json:"error"`
}
type OutputValue struct {
Value ExplanationOfBenefits `json:"value"`
}
type ErrorDetails struct {
Message string `json:"message"`
}
func getExtractionSchema() ExtractSchema {
return ExtractSchema{
Type: "object",
Properties: map[string]interface{}{
"member_id": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The unique identification number assigned to the insured member or subscriber.",
},
"eob_number": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The unique identifier for this Explanation of Benefits document.",
},
"plan_name": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The name of the health insurance plan or product.",
},
"group_number": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The group or employer number associated with the health plan.",
},
"subscriber_name": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The name of the primary insured individual or policyholder.",
},
"patient_name": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The full name of the individual who received the medical services.",
},
"provider_name": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The name of the healthcare provider, facility, or organization.",
},
"date_processed": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The date on which this claim or EOB was processed.",
"extend:type": "date",
},
"benefit_period_start": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The start date of the benefit period.",
"extend:type": "date",
},
"benefit_period_end": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The end date of the benefit period.",
"extend:type": "date",
},
"amount_billed": map[string]interface{}{
"type": "object",
"extend:type": "currency",
"description": "The total amount billed by the provider.",
},
"amount_allowed": map[string]interface{}{
"type": "object",
"extend:type": "currency",
"description": "The total amount allowed by the health plan.",
},
"discounts_and_reductions": map[string]interface{}{
"type": "object",
"extend:type": "currency",
"description": "The total amount of discounts and reductions.",
},
"health_plan_responsibility": map[string]interface{}{
"type": "object",
"extend:type": "currency",
"description": "The total amount paid or payable by the health plan.",
},
"patient_responsibility": map[string]interface{}{
"type": "object",
"extend:type": "currency",
"description": "The total amount the patient may owe.",
},
"deductible_maximum": map[string]interface{}{
"type": "object",
"extend:type": "currency",
"description": "The total deductible maximum.",
},
"deductible_met_to_date": map[string]interface{}{
"type": "object",
"extend:type": "currency",
"description": "The cumulative amount of deductible met.",
},
"out_of_pocket_maximum": map[string]interface{}{
"type": "object",
"extend:type": "currency",
"description": "The total out-of-pocket maximum.",
},
"out_of_pocket_met_to_date": map[string]interface{}{
"type": "object",
"extend:type": "currency",
"description": "The cumulative amount of out-of-pocket expenses met.",
},
"claim_line_items": map[string]interface{}{
"type": "array",
"description": "The individual service lines or procedures included in this claim.",
},
},
Required: []string{
"member_id", "plan_name", "eob_number", "group_number", "patient_name",
"amount_billed", "provider_name", "amount_allowed", "date_processed",
"subscriber_name", "claim_line_items", "benefit_period_end", "deductible_maximum",
"benefit_period_start", "out_of_pocket_maximum", "deductible_met_to_date",
"patient_responsibility", "discounts_and_reductions", "out_of_pocket_met_to_date",
"health_plan_responsibility",
},
}
}
func fileToDataURL(filePath string) (string, error) {
fileBuffer, err := os.ReadFile(filePath)
if err != nil {
return "", err
}
encoded := base64.StdEncoding.EncodeToString(fileBuffer)
return "data:application/octet-stream;base64," + encoded, nil
}
func createExtractRun(apiKey string, dataURL string) (*ExtractRunResponse, error) {
schema := getExtractionSchema()
reqBody := ExtractRunRequest{
File: FileInput{URL: dataURL},
Config: ExtractConfig{Schema: schema},
}
jsonBody, err := json.Marshal(reqBody)
if err != nil {
return nil, err
}
req, err := http.NewRequest("POST", "https://api.extend.ai/api/extract-runs", bytes.NewReader(jsonBody))
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var result ExtractRunResponse
if err := json.Unmarshal(body, &result); err != nil {
return nil, err
}
return &result, nil
}
func pollExtractRun(apiKey string, runID string, maxAttempts int, interval time.Duration) (*ExtractRunResponse, error) {
for attempt := 0; attempt < maxAttempts; attempt++ {
req, err := http.NewRequest("GET", "https://api.extend.ai/api/extract-runs/"+runID, nil)
if err != nil {
return nil, err
}
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("Content-Type", "application/json")
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
body, err := io.ReadAll(resp.Body)
if err != nil {
return nil, err
}
var result ExtractRunResponse
if err := json.Unmarshal(body, &result); err != nil {
return nil, err
}
if result.Status == "PROCESSED" || result.Status == "FAILED" {
return &result, nil
}
if attempt < maxAttempts-1 {
time.Sleep(interval)
}
}
return nil, fmt.Errorf("extraction polling timed out after %d attempts", maxAttempts)
}
func ProcessExplanationOfBenefits(filePath string) (*ExplanationOfBenefits, error) {
apiKey := os.Getenv("EXTEND_API_KEY")
if apiKey == "" {
return nil, fmt.Errorf("EXTEND_API_KEY environment variable not set")
}
dataURL, err := fileToDataURL(filePath)
if err != nil {
return nil, err
}
fmt.Printf("\n📄 Extracting EOB from: %s\n", filePath)
extractRun, err := createExtractRun(apiKey, dataURL)
if err != nil {
return nil, err
}
extractRun, err = pollExtractRun(apiKey, extractRun.ID, 120, 1*time.Second)
if err != nil {
return nil, err
}
if extractRun.Status == "PROCESSED" {
eobData := &extractRun.Output.Value
fmt.Println("\n✅ Extraction successful.\n")
fmt.Println("=== EXPLANATION OF BENEFITS SUMMARY ===\n")
fmt.Println("📋 MEMBER & CLAIM INFO")
fmt.Printf(" Member ID: %v\n", eobData.MemberID)
fmt.Printf(" Subscriber: %v\n", eobData.SubscriberName)
fmt.Printf(" Patient: %v\n", eobData.PatientName)
fmt.Printf(" Plan: %v\n", eobData.PlanName)
fmt.Printf(" Group #: %v\n", eobData.GroupNumber)
fmt.Printf(" EOB #: %v\n", eobData.EOBNumber)
fmt.Printf(" Processed: %v\n\n", eobData.DateProcessed)
fmt.Println("📅 BENEFIT PERIOD")
fmt.Printf(" Start: %v\n", eobData.BenefitPeriodStart)
fmt.Printf(" End: %v\n\n", eobData.BenefitPeriodEnd)
fmt.Println("🏥 PROVIDER & SERVICE SUMMARY")
fmt.Printf(" Provider: %v\n", eobData.ProviderName)
if eobData.AmountBilled != nil {
fmt.Printf(" Amount Billed: %v %v\n", eobData.AmountBilled.Amount, eobData.AmountBilled.ISO4217CurrencyCode)
}
if eobData.AmountAllowed != nil {
fmt.Printf(" Amount Allowed: %v %v\n", eobData.AmountAllowed.Amount, eobData.AmountAllowed.ISO4217CurrencyCode)
}
if eobData.DiscountsAndReductions != nil {
fmt.Printf(" Discounts & Reductions: %v %v\n\n", eobData.DiscountsAndReductions.Amount, eobData.DiscountsAndReductions.ISO4217CurrencyCode)
}
fmt.Println("💰 FINANCIAL RESPONSIBILITY")
if eobData.HealthPlanResponsibility != nil {
fmt.Printf(" Plan Pays: %v %v\n", eobData.HealthPlanResponsibility.Amount, eobData.HealthPlanResponsibility.ISO4217CurrencyCode)
}
if eobData.PatientResponsibility != nil {
fmt.Printf(" You Owe: %v %v\n\n", eobData.PatientResponsibility.Amount, eobData.PatientResponsibility.ISO4217CurrencyCode)
}
fmt.Println("📊 BENEFIT PERIOD ACCUMULATORS")
if eobData.DeductibleMaximum != nil {
fmt.Printf(" Deductible Maximum: %v %v\n", eobData.DeductibleMaximum.Amount, eobData.DeductibleMaximum.ISO4217CurrencyCode)
}
if eobData.DeductibleMetToDate != nil {
fmt.Printf(" Deductible Met to Date: %v %v\n", eobData.DeductibleMetToDate.Amount, eobData.DeductibleMetToDate.ISO4217CurrencyCode)
}
if eobData.OutOfPocketMaximum != nil {
fmt.Printf(" Out-of-Pocket Maximum: %v %v\n", eobData.OutOfPocketMaximum.Amount, eobData.OutOfPocketMaximum.ISO4217CurrencyCode)
}
if eobData.OutOfPocketMetToDate != nil {
fmt.Printf(" Out-of-Pocket Met to Date: %v %v\n\n", eobData.OutOfPocketMetToDate.Amount, eobData.OutOfPocketMetToDate.ISO4217CurrencyCode)
}
if len(eobData.ClaimLineItems) > 0 {
fmt.Println("📝 CLAIM LINE ITEMS\n")
for idx, item := range eobData.ClaimLineItems {
fmt.Printf(" Line %d: %v\n", idx+1, item.ServiceDescription)
endDateStr := ""
if item.ServiceEndDate != nil {
endDateStr = fmt.Sprintf(" to %v", *item.ServiceEndDate)
}
fmt.Printf(" Service Date: %v%s\n", item.ServiceStartDate, endDateStr)
fmt.Printf(" Billed: %v | Allowed: %v\n", item.AmountBilled, item.AmountAllowed)
fmt.Printf(" Plan Pays: %v | You Pay: %v\n", item.HealthPlanResponsibility, item.PatientResponsibility)
if item.Notes != nil {
fmt.Printf(" Notes: %v\n", *item.Notes)
}
fmt.Println()
}
}
return eobData, nil
}
return nil, fmt.Errorf("extraction failed with status: %s", extractRun.Status)
}
func main() {
filePath := "./eob.pdf"
if len(os.Args) > 1 {
filePath = os.Args[1]
}
_, err := ProcessExplanationOfBenefits(filePath)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
}// Deploy the "Explanation of Benefits" pipeline to YOUR Extend account.
//
// The workflow below is fully self-contained — every EXTRACT/CLASSIFY/SPLIT
// step carries its extractor/classifier/splitter config INLINE, so this is a
// single API call. No processors to create or wire up beforehand.
// Idempotent: the created workflow id is cached in .extend/explanation-of-benefits-eob-extractor.json,
// so re-running updates the existing workflow instead of duplicating it.
//
// Usage:
// export EXTEND_API_KEY=sk_... (from https://dashboard.extend.ai → API Keys)
// npx tsx provision.ts
//
// Generated by doc1 (template: explanation-of-benefits-eob-extractor).
import fs from "node:fs";
import path from "node:path";
const API = "https://api.extend.ai";
const VERSION = "2026-02-09";
const API_KEY = process.env.EXTEND_API_KEY;
if (!API_KEY) { console.error("Set EXTEND_API_KEY first."); process.exit(1); }
const STATE_DIR = path.join(process.cwd(), ".extend");
const STATE_FILE = path.join(STATE_DIR, "explanation-of-benefits-eob-extractor.json");
type State = { workflowId?: string };
const state: State = fs.existsSync(STATE_FILE)
? JSON.parse(fs.readFileSync(STATE_FILE, "utf8"))
: {};
function saveState() {
fs.mkdirSync(STATE_DIR, { recursive: true });
fs.writeFileSync(STATE_FILE, JSON.stringify(state, null, 2));
}
async function api(method: string, pathName: string, body?: unknown) {
const res = await fetch(API + pathName, {
method,
headers: {
Authorization: `Bearer ${API_KEY}`,
"x-extend-api-version": VERSION,
...(body ? { "Content-Type": "application/json" } : {}),
},
body: body ? JSON.stringify(body) : undefined,
});
const data = await res.json().catch(() => ({}));
if (!res.ok) throw new Error(`${method} ${pathName} failed (${res.status}): ${JSON.stringify(data).slice(0, 300)}`);
return data;
}
// ── Workflow definition — extractor/classifier/splitter configs inline ──────
const WORKFLOW = {
"name": "Explanation of Benefits Processing Pipeline",
"steps": [
{
"name": "startTrigger1",
"type": "TRIGGER",
"next": [
{
"step": "parse1"
}
]
},
{
"name": "parse1",
"type": "PARSE",
"config": {
"parseConfig": {
"blockOptions": {
"text": {
"agentic": {
"enabled": true
},
"signatureDetectionEnabled": true
},
"tables": {
"agentic": {
"enabled": true
},
"tableHeaderContinuationEnabled": true
},
"figures": {
"enabled": true
}
},
"chunkingStrategy": {
"type": "page",
"options": {}
}
}
},
"next": [
{
"step": "extraction2"
}
]
},
{
"name": "extraction2",
"type": "EXTRACT",
"config": {
"extractorConfig": {
"schema": {
"type": "object",
"required": [
"member_id",
"plan_name",
"eob_number",
"group_number",
"patient_name",
"amount_billed",
"provider_name",
"amount_allowed",
"date_processed",
"subscriber_name",
"claim_line_items",
"benefit_period_end",
"deductible_maximum",
"benefit_period_start",
"out_of_pocket_maximum",
"deductible_met_to_date",
"patient_responsibility",
"discounts_and_reductions",
"out_of_pocket_met_to_date",
"health_plan_responsibility"
],
"properties": {
"member_id": {
"type": [
"string",
"null"
],
"description": "The unique identification number assigned to the insured member or subscriber. This is used by the health plan to identify the covered individual. May be labeled as 'Member ID', 'Subscriber ID', or similar."
},
"plan_name": {
"type": [
"string",
"null"
],
"description": "The name of the health insurance plan or product under which the claim was processed. May appear as 'Plan Name', 'Product', or similar."
},
"eob_number": {
"type": [
"string",
"null"
],
"description": "The unique identifier for this Explanation of Benefits (EOB) document or claim. This is the primary reference number used to track this EOB. May include numbers, letters, or special characters. Common labels include 'Claim #', 'EOB #', or similar."
},
"group_number": {
"type": [
"string",
"null"
],
"description": "The group or employer number associated with the health plan. This identifies the employer or group plan under which the member is covered. Commonly labeled as 'Group #', 'Group Number', etc."
},
"patient_name": {
"type": [
"string",
"null"
],
"description": "The full name of the individual who received the medical services. May be labeled as 'Patient', 'Covered Person', or similar."
},
"amount_billed": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total amount billed by the provider for all services included in this claim. This is the original charge before any discounts, reductions, or insurance adjustments.",
"extend:type": "currency",
"additionalProperties": false
},
"provider_name": {
"type": [
"string",
"null"
],
"description": "The name of the healthcare provider, facility, or organization that rendered the services for this claim. May be labeled as 'Provider', 'Facility', or similar."
},
"amount_allowed": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total amount allowed by the health plan for the services provided, after discounts and reductions. This is the maximum amount considered for payment.",
"extend:type": "currency",
"additionalProperties": false
},
"date_processed": {
"type": [
"string",
"null"
],
"description": "The date on which this claim or EOB was processed by the health plan. May be labeled as 'Date Processed', 'Processed On', or similar.",
"extend:type": "date"
},
"subscriber_name": {
"type": [
"string",
"null"
],
"description": "The name of the primary insured individual or policyholder. This is the person who holds the insurance policy, sometimes labeled as 'Subscriber', 'Participant', or 'Member'."
},
"claim_line_items": {
"type": "array",
"items": {
"type": "object",
"required": [
"notes",
"copay_amount",
"amount_billed",
"amount_allowed",
"service_end_date",
"deductible_amount",
"amount_not_covered",
"coinsurance_amount",
"service_start_date",
"service_description",
"patient_responsibility",
"discounts_and_reductions",
"health_plan_responsibility"
],
"properties": {
"notes": {
"type": [
"string",
"null"
],
"description": "Any notes, remarks, or explanations related to this service line, such as denial reasons, bundling, or special instructions. May be referenced by footnotes or symbols."
},
"copay_amount": {
"type": [
"number",
"null"
],
"description": "The copayment amount the patient is responsible for on this service line."
},
"amount_billed": {
"type": [
"number",
"null"
],
"description": "The amount billed by the provider for this specific service line, before any discounts or reductions."
},
"amount_allowed": {
"type": [
"number",
"null"
],
"description": "The amount allowed by the health plan for this service line after discounts and reductions."
},
"service_end_date": {
"type": [
"string",
"null"
],
"description": "The date on which the service or procedure ended, if applicable. May be omitted if service occurred on a single day.",
"extend:type": "date"
},
"deductible_amount": {
"type": [
"number",
"null"
],
"description": "The portion of this service line applied to the patient's deductible."
},
"amount_not_covered": {
"type": [
"number",
"null"
],
"description": "The amount for this service line that is not covered by the health plan and is the patient's responsibility."
},
"coinsurance_amount": {
"type": [
"number",
"null"
],
"description": "The coinsurance amount the patient is responsible for on this service line."
},
"service_start_date": {
"type": [
"string",
"null"
],
"description": "The date on which the service or procedure began or was rendered. May be labeled as 'Service Date', 'Date of Service', or similar.",
"extend:type": "date"
},
"service_description": {
"type": [
"string",
"null"
],
"description": "A description of the medical service, procedure, or supply provided. May include procedure names, codes, or other identifying information."
},
"patient_responsibility": {
"type": [
"number",
"null"
],
"description": "The total amount the patient is responsible for on this service line, including deductible, copay, coinsurance, and non-covered amounts."
},
"discounts_and_reductions": {
"type": [
"number",
"null"
],
"description": "The amount of discounts, reductions, or adjustments applied to this service line by the health plan."
},
"health_plan_responsibility": {
"type": [
"number",
"null"
],
"description": "The amount paid or payable by the health plan for this service line."
}
},
"additionalProperties": false
},
"description": "The individual service lines or procedures included in this claim. Each item represents a specific service, procedure, or charge, and includes details about dates, amounts, and benefit application. Format and labeling may vary widely across EOBs."
},
"benefit_period_end": {
"type": [
"string",
"null"
],
"description": "The end date of the benefit period relevant to this EOB or claim. This is the end of the coverage period for deductibles and out-of-pocket calculations.",
"extend:type": "date"
},
"deductible_maximum": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total deductible maximum for the benefit period for the patient or family, as specified by the plan.",
"extend:type": "currency",
"additionalProperties": false
},
"benefit_period_start": {
"type": [
"string",
"null"
],
"description": "The start date of the benefit period relevant to this EOB or claim. This is the beginning of the coverage period for deductibles and out-of-pocket calculations.",
"extend:type": "date"
},
"out_of_pocket_maximum": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total out-of-pocket maximum for the benefit period for the patient or family, as specified by the plan.",
"extend:type": "currency",
"additionalProperties": false
},
"deductible_met_to_date": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The cumulative amount of deductible met by the patient for the current benefit period as of this EOB. This reflects progress toward the annual deductible.",
"extend:type": "currency",
"additionalProperties": false
},
"patient_responsibility": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total amount the patient may owe to the provider for these services, after insurance payments and adjustments. This may include deductibles, copays, coinsurance, and non-covered amounts.",
"extend:type": "currency",
"additionalProperties": false
},
"discounts_and_reductions": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total amount of discounts, reductions, or adjustments applied to the billed charges by the health plan. This may include network discounts, negotiated rates, or other reductions.",
"extend:type": "currency",
"additionalProperties": false
},
"out_of_pocket_met_to_date": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The cumulative amount of out-of-pocket expenses met by the patient for the current benefit period as of this EOB. This includes deductibles, copays, and coinsurance.",
"extend:type": "currency",
"additionalProperties": false
},
"health_plan_responsibility": {
"type": "object",
"required": [
"amount",
"iso_4217_currency_code"
],
"properties": {
"amount": {
"type": [
"number",
"null"
]
},
"iso_4217_currency_code": {
"type": [
"string",
"null"
]
}
},
"description": "The total amount paid or payable by the health plan for this claim. This is the insurer's share of the allowed amount.",
"extend:type": "currency",
"additionalProperties": false
}
},
"additionalProperties": false
},
"baseProcessor": "extraction_performance"
}
}
}
]
};
async function main() {
console.log(`Deploying "${WORKFLOW.name}"…`);
if (state.workflowId) {
console.log(`✓ workflow already provisioned (${state.workflowId}) — updating steps`);
await api("POST", `/workflows/${state.workflowId}`, { steps: WORKFLOW.steps });
} else {
// Reuse an existing workflow with the same name if one exists (e.g. a
// previous run's state file was lost) instead of creating a duplicate.
try {
const list = await api("GET", `/workflows?name=${encodeURIComponent(WORKFLOW.name)}`);
const items = (list.data ?? list.items ?? []) as Array<{ name?: string; id?: string }>;
const existing = items.find((x) => x.name === WORKFLOW.name);
if (existing?.id) {
state.workflowId = existing.id; saveState();
console.log(`✓ workflow "${WORKFLOW.name}" found in your account (${existing.id}) — updating steps`);
await api("POST", `/workflows/${existing.id}`, { steps: WORKFLOW.steps });
}
} catch { /* lookup is best-effort; fall through to create */ }
if (!state.workflowId) {
const created = await api("POST", "/workflows", WORKFLOW);
const wfId = created.id ?? created.workflow?.id;
if (!wfId) throw new Error("Could not read created workflow id from response");
state.workflowId = wfId; saveState();
console.log(`+ created workflow (${wfId})`);
}
}
// Deploy the current draft as a new version so the workflow is runnable —
// best-effort: some accounts/plans may not require this explicit step.
await api("POST", `/workflows/${state.workflowId}/versions`, {}).catch(() => {});
console.log("\nDone. Run documents through it with:");
console.log(` POST ${API}/workflow_runs { workflow: { id: "${state.workflowId}" }, file: { url: "https://…" } }`);
console.log("Or open the workflow in the Extend dashboard to review and deploy it.");
}
main().catch((e) => { console.error(e.message ?? e); process.exit(1); });
import os
import sys
import json
import pathlib
from typing import TypedDict, Optional, Any
from extend_ai import Extend
API_KEY = os.environ.get("EXTEND_API_KEY")
if not API_KEY:
print("Set EXTEND_API_KEY first.")
sys.exit(1)
STATE_DIR = pathlib.Path.cwd() / ".extend"
STATE_FILE = STATE_DIR / "explanation-of-benefits-eob-extractor.json"
class State(TypedDict, total=False):
workflow_id: Optional[str]
def load_state() -> State:
if STATE_FILE.exists():
return json.loads(STATE_FILE.read_text())
return {}
def save_state(state: State) -> None:
STATE_DIR.mkdir(parents=True, exist_ok=True)
STATE_FILE.write_text(json.dumps(state, indent=2))
WORKFLOW = {
"name": "Explanation of Benefits Processing Pipeline",
"steps": [
{
"name": "startTrigger1",
"type": "TRIGGER",
"next": [{"step": "parse1"}],
},
{
"name": "parse1",
"type": "PARSE",
"config": {
"parseConfig": {
"blockOptions": {
"text": {
"agentic": {"enabled": True},
"signatureDetectionEnabled": True,
},
"tables": {
"agentic": {"enabled": True},
"tableHeaderContinuationEnabled": True,
},
"figures": {"enabled": True},
},
"chunkingStrategy": {"type": "page", "options": {}},
}
},
"next": [{"step": "extraction2"}],
},
{
"name": "extraction2",
"type": "EXTRACT",
"config": {
"extractorConfig": {
"schema": {
"type": "object",
"required": [
"member_id",
"plan_name",
"eob_number",
"group_number",
"patient_name",
"amount_billed",
"provider_name",
"amount_allowed",
"date_processed",
"subscriber_name",
"claim_line_items",
"benefit_period_end",
"deductible_maximum",
"benefit_period_start",
"out_of_pocket_maximum",
"deductible_met_to_date",
"patient_responsibility",
"discounts_and_reductions",
"out_of_pocket_met_to_date",
"health_plan_responsibility",
],
"properties": {
"member_id": {
"type": ["string", "null"],
"description": "The unique identification number assigned to the insured member or subscriber. This is used by the health plan to identify the covered individual. May be labeled as 'Member ID', 'Subscriber ID', or similar.",
},
"plan_name": {
"type": ["string", "null"],
"description": "The name of the health insurance plan or product under which the claim was processed. May appear as 'Plan Name', 'Product', or similar.",
},
"eob_number": {
"type": ["string", "null"],
"description": "The unique identifier for this Explanation of Benefits (EOB) document or claim. This is the primary reference number used to track this EOB. May include numbers, letters, or special characters. Common labels include 'Claim #', 'EOB #', or similar.",
},
"group_number": {
"type": ["string", "null"],
"description": "The group or employer number associated with the health plan. This identifies the employer or group plan under which the member is covered. Commonly labeled as 'Group #', 'Group Number', etc.",
},
"patient_name": {
"type": ["string", "null"],
"description": "The full name of the individual who received the medical services. May be labeled as 'Patient', 'Covered Person', or similar.",
},
"amount_billed": {
"type": "object",
"required": ["amount", "iso_4217_currency_code"],
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]},
},
"description": "The total amount billed by the provider for all services included in this claim. This is the original charge before any discounts, reductions, or insurance adjustments.",
"extend:type": "currency",
"additionalProperties": False,
},
"provider_name": {
"type": ["string", "null"],
"description": "The name of the healthcare provider, facility, or organization that rendered the services for this claim. May be labeled as 'Provider', 'Facility', or similar.",
},
"amount_allowed": {
"type": "object",
"required": ["amount", "iso_4217_currency_code"],
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]},
},
"description": "The total amount allowed by the health plan for the services provided, after discounts and reductions. This is the maximum amount considered for payment.",
"extend:type": "currency",
"additionalProperties": False,
},
"date_processed": {
"type": ["string", "null"],
"description": "The date on which this claim or EOB was processed by the health plan. May be labeled as 'Date Processed', 'Processed On', or similar.",
"extend:type": "date",
},
"subscriber_name": {
"type": ["string", "null"],
"description": "The name of the primary insured individual or policyholder. This is the person who holds the insurance policy, sometimes labeled as 'Subscriber', 'Participant', or 'Member'.",
},
"claim_line_items": {
"type": "array",
"items": {
"type": "object",
"required": [
"notes",
"copay_amount",
"amount_billed",
"amount_allowed",
"service_end_date",
"deductible_amount",
"amount_not_covered",
"coinsurance_amount",
"service_start_date",
"service_description",
"patient_responsibility",
"discounts_and_reductions",
"health_plan_responsibility",
],
"properties": {
"notes": {
"type": ["string", "null"],
"description": "Any notes, remarks, or explanations related to this service line, such as denial reasons, bundling, or special instructions. May be referenced by footnotes or symbols.",
},
"copay_amount": {
"type": ["number", "null"],
"description": "The copayment amount the patient is responsible for on this service line.",
},
"amount_billed": {
"type": ["number", "null"],
"description": "The amount billed by the provider for this specific service line, before any discounts or reductions.",
},
"amount_allowed": {
"type": ["number", "null"],
"description": "The amount allowed by the health plan for this service line after discounts and reductions.",
},
"service_end_date": {
"type": ["string", "null"],
"description": "The date on which the service or procedure ended, if applicable. May be omitted if service occurred on a single day.",
"extend:type": "date",
},
"deductible_amount": {
"type": ["number", "null"],
"description": "The portion of this service line applied to the patient's deductible.",
},
"amount_not_covered": {
"type": ["number", "null"],
"description": "The amount for this service line that is not covered by the health plan and is the patient's responsibility.",
},
"coinsurance_amount": {
"type": ["number", "null"],
"description": "The coinsurance amount the patient is responsible for on this service line.",
},
"service_start_date": {
"type": ["string", "null"],
"description": "The date on which the service or procedure began or was rendered. May be labeled as 'Service Date', 'Date of Service', or similar.",
"extend:type": "date",
},
"service_description": {
"type": ["string", "null"],
"description": "A description of the medical service, procedure, or supply provided. May include procedure names, codes, or other identifying information.",
},
"patient_responsibility": {
"type": ["number", "null"],
"description": "The total amount the patient is responsible for on this service line, including deductible, copay, coinsurance, and non-covered amounts.",
},
"discounts_and_reductions": {
"type": ["number", "null"],
"description": "The amount of discounts, reductions, or adjustments applied to this service line by the health plan.",
},
"health_plan_responsibility": {
"type": ["number", "null"],
"description": "The amount paid or payable by the health plan for this service line.",
},
},
"additionalProperties": False,
},
"description": "The individual service lines or procedures included in this claim. Each item represents a specific service, procedure, or charge, and includes details about dates, amounts, and benefit application. Format and labeling may vary widely across EOBs.",
},
"benefit_period_end": {
"type": ["string", "null"],
"description": "The end date of the benefit period relevant to this EOB or claim. This is the end of the coverage period for deductibles and out-of-pocket calculations.",
"extend:type": "date",
},
"deductible_maximum": {
"type": "object",
"required": ["amount", "iso_4217_currency_code"],
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]},
},
"description": "The total deductible maximum for the benefit period for the patient or family, as specified by the plan.",
"extend:type": "currency",
"additionalProperties": False,
},
"benefit_period_start": {
"type": ["string", "null"],
"description": "The start date of the benefit period relevant to this EOB or claim. This is the beginning of the coverage period for deductibles and out-of-pocket calculations.",
"extend:type": "date",
},
"out_of_pocket_maximum": {
"type": "object",
"required": ["amount", "iso_4217_currency_code"],
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]},
},
"description": "The total out-of-pocket maximum for the benefit period for the patient or family, as specified by the plan.",
"extend:type": "currency",
"additionalProperties": False,
},
"deductible_met_to_date": {
"type": "object",
"required": ["amount", "iso_4217_currency_code"],
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]},
},
"description": "The cumulative amount of deductible met by the patient for the current benefit period as of this EOB. This reflects progress toward the annual deductible.",
"extend:type": "currency",
"additionalProperties": False,
},
"patient_responsibility": {
"type": "object",
"required": ["amount", "iso_4217_currency_code"],
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]},
},
"description": "The total amount the patient may owe to the provider for these services, after insurance payments and adjustments. This may include deductibles, copays, coinsurance, and non-covered amounts.",
"extend:type": "currency",
"additionalProperties": False,
},
"discounts_and_reductions": {
"type": "object",
"required": ["amount", "iso_4217_currency_code"],
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]},
},
"description": "The total amount of discounts, reductions, or adjustments applied to the billed charges by the health plan. This may include network discounts, negotiated rates, or other reductions.",
"extend:type": "currency",
"additionalProperties": False,
},
"out_of_pocket_met_to_date": {
"type": "object",
"required": ["amount", "iso_4217_currency_code"],
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]},
},
"description": "The cumulative amount of out-of-pocket expenses met by the patient for the current benefit period as of this EOB. This includes deductibles, copays, and coinsurance.",
"extend:type": "currency",
"additionalProperties": False,
},
"health_plan_responsibility": {
"type": "object",
"required": ["amount", "iso_4217_currency_code"],
"properties": {
"amount": {"type": ["number", "null"]},
"iso_4217_currency_code": {"type": ["string", "null"]},
},
"description": "The total amount paid or payable by the health plan for this claim. This is the insurer's share of the allowed amount.",
"extend:type": "currency",
"additionalProperties": False,
},
},
"additionalProperties": False,
},
"baseProcessor": "extraction_performance",
}
},
},
],
}
async def main() -> None:
client = Extend(token=API_KEY)
state = load_state()
print(f"Deploying \"{WORKFLOW['name']}\"…")
if state.get("workflow_id"):
workflow_id = state["workflow_id"]
print(f"✓ workflow already provisioned ({workflow_id}) — updating steps")
await client.workflows.update(
workflow_id, steps=WORKFLOW["steps"]
)
else:
try:
workflows_response = await client.workflows.list(
name=WORKFLOW["name"]
)
items: list[dict[str, Any]] = getattr(
workflows_response, "data", None
) or getattr(workflows_response, "items", [])
existing = next(
(w for w in items if w.get("name") == WORKFLOW["name"]),
None,
)
if existing and existing.get("id"):
workflow_id = existing["id"]
state["workflow_id"] = workflow_id
save_state(state)
print(
f"✓ workflow \"{WORKFLOW['name']}\" found in your account ({workflow_id}) — updating steps"
)
await client.workflows.update(workflow_id, steps=WORKFLOW["steps"])
except Exception:
pass
if not state.get("workflow_id"):
created_workflow = await client.workflows.create(**WORKFLOW)
workflow_id = getattr(
created_workflow, "id", None
) or getattr(getattr(created_workflow, "workflow", None), "id", None)
if not workflow_id:
raise ValueError(
"Could not read created workflow id from response"
)
state["workflow_id"] = workflow_id
save_state(state)
print(f"+ created workflow ({workflow_id})")
workflow_id = state["workflow_id"]
try:
await client.workflows.create_version(workflow_id)
except Exception:
pass
print("\nDone. Run documents through it with:")
print(
f" POST https://api.extend.ai/workflow_runs {{ workflow: {{ id: \"{workflow_id}\" }}, file: {{ url: \"https://…\" }} }}"
)
print(
"Or open the workflow in the Extend dashboard to review and deploy it."
)
if __name__ == "__main__":
import asyncio
try:
asyncio.run(main())
except Exception as e:
print(str(e) if hasattr(e, "__str__") else e, file=sys.stderr)
sys.exit(1)// This uses the Extend REST API directly because Extend has no official Java SDK yet.
// Call Extend's REST API at https://api.extend.ai with Bearer token authentication.
import java.io.IOException;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class Provision {
private static final String API = "https://api.extend.ai";
private static final String VERSION = "2026-02-09";
private static final String API_KEY = System.getenv("EXTEND_API_KEY");
private static final Path STATE_DIR = Paths.get(System.getProperty("user.dir"), ".extend");
private static final Path STATE_FILE = STATE_DIR.resolve("explanation-of-benefits-eob-extractor.json");
private static final HttpClient httpClient = HttpClient.newHttpClient();
static class State {
String workflowId;
static State load() throws IOException {
State state = new State();
if (Files.exists(STATE_FILE)) {
String json = Files.readString(STATE_FILE);
state.workflowId = extractWorkflowId(json);
}
return state;
}
void save() throws IOException {
Files.createDirectories(STATE_DIR);
String json = "{\"workflowId\": " +
(workflowId != null ? "\"" + workflowId + "\"" : "null") + "}";
Files.writeString(STATE_FILE, json);
}
private static String extractWorkflowId(String json) {
int idx = json.indexOf("\"workflowId\":");
if (idx < 0) return null;
int start = json.indexOf("\"", idx + 14);
if (start < 0) return null;
int end = json.indexOf("\"", start + 1);
if (end < 0) return null;
return json.substring(start + 1, end);
}
}
static class ApiResponse {
String id;
String workflow_id;
List<Map<String, Object>> data;
List<Map<String, Object>> items;
static ApiResponse fromJson(String json) {
ApiResponse resp = new ApiResponse();
resp.id = extractField(json, "\"id\"");
resp.workflow_id = extractField(json, "\"workflow_id\"");
resp.data = parseArray(json, "\"data\"");
resp.items = parseArray(json, "\"items\"");
return resp;
}
private static String extractField(String json, String key) {
int idx = json.indexOf(key);
if (idx < 0) return null;
int colonIdx = json.indexOf(":", idx);
if (colonIdx < 0) return null;
int start = json.indexOf("\"", colonIdx);
if (start < 0) return null;
int end = json.indexOf("\"", start + 1);
if (end < 0) return null;
return json.substring(start + 1, end);
}
private static List<Map<String, Object>> parseArray(String json, String key) {
return null;
}
}
static String api(String method, String pathName, String body) throws Exception {
if (API_KEY == null || API_KEY.isEmpty()) {
throw new IllegalStateException("Set EXTEND_API_KEY environment variable first.");
}
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(new URI(API + pathName))
.method(method, body != null
? HttpRequest.BodyPublishers.ofString(body)
: HttpRequest.BodyPublishers.noBody())
.header("Authorization", "Bearer " + API_KEY)
.header("x-extend-api-version", VERSION);
if (body != null) {
requestBuilder.header("Content-Type", "application/json");
}
HttpResponse<String> response = httpClient.send(
requestBuilder.build(),
HttpResponse.BodyHandlers.ofString()
);
if (response.statusCode() < 200 || response.statusCode() >= 300) {
String msg = response.body();
if (msg.length() > 300) msg = msg.substring(0, 300);
throw new IOException(method + " " + pathName + " failed (" +
response.statusCode() + "): " + msg);
}
return response.body();
}
static String buildWorkflowJson() {
StringBuilder sb = new StringBuilder();
sb.append("{\n");
sb.append(" \"name\": \"Explanation of Benefits Processing Pipeline\",\n");
sb.append(" \"steps\": [\n");
// startTrigger1
sb.append(" {\n");
sb.append(" \"name\": \"startTrigger1\",\n");
sb.append(" \"type\": \"TRIGGER\",\n");
sb.append(" \"next\": [{\"step\": \"parse1\"}]\n");
sb.append(" },\n");
// parse1
sb.append(" {\n");
sb.append(" \"name\": \"parse1\",\n");
sb.append(" \"type\": \"PARSE\",\n");
sb.append(" \"config\": {\n");
sb.append(" \"parseConfig\": {\n");
sb.append(" \"blockOptions\": {\n");
sb.append(" \"text\": {\n");
sb.append(" \"agentic\": {\"enabled\": true},\n");
sb.append(" \"signatureDetectionEnabled\": true\n");
sb.append(" },\n");
sb.append(" \"tables\": {\n");
sb.append(" \"agentic\": {\"enabled\": true},\n");
sb.append(" \"tableHeaderContinuationEnabled\": true\n");
sb.append(" },\n");
sb.append(" \"figures\": {\"enabled\": true}\n");
sb.append(" },\n");
sb.append(" \"chunkingStrategy\": {\n");
sb.append(" \"type\": \"page\",\n");
sb.append(" \"options\": {}\n");
sb.append(" }\n");
sb.append(" }\n");
sb.append(" },\n");
sb.append(" \"next\": [{\"step\": \"extraction2\"}]\n");
sb.append(" },\n");
// extraction2 with full schema
sb.append(" {\n");
sb.append(" \"name\": \"extraction2\",\n");
sb.append(" \"type\": \"EXTRACT\",\n");
sb.append(" \"config\": {\n");
sb.append(" \"extractorConfig\": {\n");
sb.append(" \"baseProcessor\": \"extraction_performance\",\n");
sb.append(" \"schema\": {\n");
sb.append(" \"type\": \"object\",\n");
sb.append(" \"additionalProperties\": false,\n");
sb.append(" \"required\": [\"member_id\",\"plan_name\",\"eob_number\",\"group_number\",\"patient_name\",\"amount_billed\",\"provider_name\",\"amount_allowed\",\"date_processed\",\"subscriber_name\",\"claim_line_items\",\"benefit_period_end\",\"deductible_maximum\",\"benefit_period_start\",\"out_of_pocket_maximum\",\"deductible_met_to_date\",\"patient_responsibility\",\"discounts_and_reductions\",\"out_of_pocket_met_to_date\",\"health_plan_responsibility\"],\n");
sb.append(" \"properties\": {\n");
// String fields
String[] stringFields = {"member_id", "plan_name", "eob_number", "group_number", "patient_name", "provider_name", "subscriber_name"};
for (String field : stringFields) {
sb.append(" \"").append(field).append("\": {\"type\": [\"string\", \"null\"]},\n");
}
// Currency fields
String[] currencyFields = {"amount_billed", "amount_allowed", "deductible_maximum", "out_of_pocket_maximum", "deductible_met_to_date", "patient_responsibility", "discounts_and_reductions", "out_of_pocket_met_to_date", "health_plan_responsibility"};
for (int i = 0; i < currencyFields.length; i++) {
String field = currencyFields[i];
sb.append(" \"").append(field).append("\": {\"type\": \"object\", \"additionalProperties\": false, \"required\": [\"amount\", \"iso_4217_currency_code\"], \"properties\": {\"amount\": {\"type\": [\"number\", \"null\"]}, \"iso_4217_currency_code\": {\"type\": [\"string\", \"null\"]}}}");
if (i < currencyFields.length - 1) sb.append(",");
sb.append("\n");
}
// Date fields
sb.append(",\n \"date_processed\": {\"type\": [\"string\", \"null\"], \"extend:type\": \"date\"},\n");
sb.append(" \"benefit_period_end\": {\"type\": [\"string\", \"null\"], \"extend:type\": \"date\"},\n");
sb.append(" \"benefit_period_start\": {\"type\": [\"string\", \"null\"], \"extend:type\": \"date\"},\n");
// claim_line_items array
sb.append(" \"claim_line_items\": {\n");
sb.append(" \"type\": \"array\",\n");
sb.append(" \"items\": {\n");
sb.append(" \"type\": \"object\",\n");
sb.append(" \"additionalProperties\": false,\n");
sb.append(" \"required\": [\"notes\",\"copay_amount\",\"amount_billed\",\"amount_allowed\",\"service_end_date\",\"deductible_amount\",\"amount_not_covered\",\"coinsurance_amount\",\"service_start_date\",\"service_description\",\"patient_responsibility\",\"discounts_and_reductions\",\"health_plan_responsibility\"],\n");
sb.append(" \"properties\": {\n");
sb.append(" \"notes\": {\"type\": [\"string\", \"null\"]},\n");
sb.append(" \"copay_amount\": {\"type\": [\"number\", \"null\"]},\n");
sb.append(" \"amount_billed\": {\"type\": [\"number\", \"null\"]},\n");
sb.append(" \"amount_allowed\": {\"type\": [\"number\", \"null\"]},\n");
sb.append(" \"deductible_amount\": {\"type\": [\"number\", \"null\"]},\n");
sb.append(" \"amount_not_covered\": {\"type\": [\"number\", \"null\"]},\n");
sb.append(" \"coinsurance_amount\": {\"type\": [\"number\", \"null\"]},\n");
sb.append(" \"service_description\": {\"type\": [\"string\", \"null\"]},\n");
sb.append(" \"patient_responsibility\": {\"type\": [\"number\", \"null\"]},\n");
sb.append(" \"discounts_and_reductions\": {\"type\": [\"number\", \"null\"]},\n");
sb.append(" \"health_plan_responsibility\": {\"type\": [\"number\", \"null\"]},\n");
sb.append(" \"service_start_date\": {\"type\": [\"string\", \"null\"], \"extend:type\": \"date\"},\n");
sb.append(" \"service_end_date\": {\"type\": [\"string\", \"null\"], \"extend:type\": \"date\"}\n");
sb.append(" }\n");
sb.append(" }\n");
sb.append(" }\n");
sb.append(" }\n");
sb.append(" }\n");
sb.append(" }\n");
sb.append(" }\n");
sb.append(" }\n");
sb.append(" ]\n");
sb.append("}\n");
return sb.toString();
}
static String buildStepsJson() {
StringBuilder sb = new StringBuilder();
sb.append("{\"steps\": [");
sb.append("{\"name\":\"startTrigger1\",\"type\":\"TRIGGER\",\"next\":[{\"step\":\"parse1\"}]},");
sb.append("{\"name\":\"parse1\",\"type\":\"PARSE\",\"config\":{\"parseConfig\":{\"blockOptions\":{\"text\":{\"agentic\":{\"enabled\":true},\"signatureDetectionEnabled\":true},\"tables\":{\"agentic\":{\"enabled\":true},\"tableHeaderContinuationEnabled\":true},\"figures\":{\"enabled\":true}},\"chunkingStrategy\":{\"type\":\"page\",\"options\":{}}}},\"next\":[{\"step\":\"extraction2\"}]},");
sb.append("{\"name\":\"extraction2\",\"type\":\"EXTRACT\",\"config\":{\"extractorConfig\":{\"baseProcessor\":\"extraction_performance\",\"schema\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"member_id\",\"plan_name\",\"eob_number\",\"group_number\",\"patient_name\",\"amount_billed\",\"provider_name\",\"amount_allowed\",\"date_processed\",\"subscriber_name\",\"claim_line_items\",\"benefit_period_end\",\"deductible_maximum\",\"benefit_period_start\",\"out_of_pocket_maximum\",\"deductible_met_to_date\",\"patient_responsibility\",\"discounts_and_reductions\",\"out_of_pocket_met_to_date\",\"health_plan_responsibility\"],\"properties\":{\"member_id\":{\"type\":[\"string\",\"null\"]},\"plan_name\":{\"type\":[\"string\",\"null\"]},\"eob_number\":{\"type\":[\"string\",\"null\"]},\"group_number\":{\"type\":[\"string\",\"null\"]},\"patient_name\":{\"type\":[\"string\",\"null\"]},\"provider_name\":{\"type\":[\"string\",\"null\"]},\"subscriber_name\":{\"type\":[\"string\",\"null\"]},\"date_processed\":{\"type\":[\"string\",\"null\"],\"extend:type\":\"date\"},\"benefit_period_start\":{\"type\":[\"string\",\"null\"],\"extend:type\":\"date\"},\"benefit_period_end\":{\"type\":[\"string\",\"null\"],\"extend:type\":\"date\"},\"amount_billed\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}}},\"amount_allowed\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}}},\"deductible_maximum\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}}},\"out_of_pocket_maximum\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}}},\"deductible_met_to_date\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}}},\"patient_responsibility\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}}},\"discounts_and_reductions\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}}},\"out_of_pocket_met_to_date\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}}},\"health_plan_responsibility\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}}},\"claim_line_items\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"additionalProperties\":false,\"required\":[\"notes\",\"copay_amount\",\"amount_billed\",\"amount_allowed\",\"service_end_date\",\"deductible_amount\",\"amount_not_covered\",\"coinsurance_amount\",\"service_start_date\",\"service_description\",\"patient_responsibility\",\"discounts_and_reductions\",\"health_plan_responsibility\"],\"properties\":{\"notes\":{\"type\":[\"string\",\"null\"]},\"copay_amount\":{\"type\":[\"number\",\"null\"]},\"amount_billed\":{\"type\":[\"number\",\"null\"]},\"amount_allowed\":{\"type\":[\"number\",\"null\"]},\"deductible_amount\":{\"type\":[\"number\",\"null\"]},\"amount_not_covered\":{\"type\":[\"number\",\"null\"]},\"coinsurance_amount\":{\"type\":[\"number\",\"null\"]},\"service_description\":{\"type\":[\"string\",\"null\"]},\"patient_responsibility\":{\"type\":[\"number\",\"null\"]},\"discounts_and_reductions\":{\"type\":[\"number\",\"null\"]},\"health_plan_responsibility\":{\"type\":[\"number\",\"null\"]},\"service_start_date\":{\"type\":[\"string\",\"null\"],\"extend:type\":\"date\"},\"service_end_date\":{\"type\":[\"string\",\"null\"],\"extend:type\":\"date\"}}}}}}}}\n");
sb.append("]}\n");
return sb.toString();
}
public static void main(String[] args) {
try {
System.out.println("Deploying \"Explanation of Benefits Processing Pipeline\"…");
State state = State.load();
String workflowName = "Explanation of Benefits Processing Pipeline";
if (state.workflowId != null && !state.workflowId.isEmpty()) {
System.out.println("✓ workflow already provisioned (" + state.workflowId + ") — updating steps");
api("POST", "/workflows/" + state.workflowId, buildStepsJson());
} else {
// Try to find existing workflow by name
try {
String encoded = URLEncoder.encode(workflowName, StandardCharsets.UTF_8);
String listResponse = api("GET", "/workflows?name=" + encoded, null);
String existingId = extractExistingWorkflowId(listResponse, workflowName);
if (existingId != null && !existingId.isEmpty()) {
state.workflowId = existingId;
state.save();
System.out.println("✓ workflow \"" + workflowName + "\" found in your account (" + existingId + ") — updating steps");
api("POST", "/workflows/" + existingId, buildStepsJson());
}
} catch (Exception e) {
// Lookup is best-effort; fall through to create
}
if (state.workflowId == null || state.workflowId.isEmpty()) {
String createResponse = api("POST", "/workflows", buildWorkflowJson());
String wfId = ApiResponse.fromJson(createResponse).id;
if (wfId == null || wfId.isEmpty()) {
throw new IOException("Could not read created workflow id from response");
}
state.workflowId = wfId;
state.save();
System.out.println("+ created workflow (" + wfId + ")");
}
}
// Deploy current draft as new version (best-effort)
try {
api("POST", "/workflows/" + state.workflowId + "/versions", "{}");
} catch (Exception e) {
// Best-effort
}
System.out.println("\nDone. Run documents through it with:");
System.out.println(" POST " + API + "/workflow_runs { workflow: { id: \"" + state.workflowId + "\" }, file: { url: \"https://…\" } }");
System.out.println("Or open the workflow in the Extend dashboard to review and deploy it.");
} catch (Exception e) {
System.err.println(e.getMessage() != null ? e.getMessage() : e.toString());
System.exit(1);
}
}
static String extractExistingWorkflowId(String json, String name) {
int idx = json.indexOf("\"name\"");
while (idx >= 0) {
int startQuote = json.indexOf("\"", idx + 7);
if (startQuote < 0) break;
int endQuote = json.indexOf("\"", startQuote + 1);
if (endQuote < 0) break;
String foundName = json.substring(startQuote + 1, endQuote);
if (foundName.equals(name)) {
int idIdx = json.lastIndexOf("\"id\"", idx);
if (idIdx >= 0) {
int idStartQuote = json.indexOf("\"", idIdx + 5);
if (idStartQuote >= 0) {
int idEndQuote = json.indexOf("\"", idStartQuote + 1);
if (idEndQuote >= 0) {
return json.substring(idStartQuote + 1, idEndQuote);
}
}
}
}
idx = json.indexOf("\"name\"", endQuote);
}
return null;
}
}// This code uses the Extend REST API directly because Extend does not publish
// an official Go SDK. It makes the same API calls that the TypeScript SDK wraps.
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"net/url"
"os"
"path/filepath"
)
const (
API = "https://api.extend.ai"
VERSION = "2026-02-09"
)
type State struct {
WorkflowID *string `json:"workflowId,omitempty"`
}
type WorkflowListResponse struct {
Data []WorkflowItem `json:"data,omitempty"`
Items []WorkflowItem `json:"items,omitempty"`
}
type WorkflowItem struct {
ID *string `json:"id,omitempty"`
Name *string `json:"name,omitempty"`
}
type CreateWorkflowResponse struct {
ID *string `json:"id,omitempty"`
Workflow *struct {
ID *string `json:"id,omitempty"`
} `json:"workflow,omitempty"`
}
var (
apiKey string
stateDir string
stateFile string
state State
client = &http.Client{}
)
func init() {
apiKey = os.Getenv("EXTEND_API_KEY")
if apiKey == "" {
fmt.Fprintf(os.Stderr, "Set EXTEND_API_KEY first.\n")
os.Exit(1)
}
cwd, err := os.Getwd()
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to get working directory: %v\n", err)
os.Exit(1)
}
stateDir = filepath.Join(cwd, ".extend")
stateFile = filepath.Join(stateDir, "explanation-of-benefits-eob-extractor.json")
if data, err := os.ReadFile(stateFile); err == nil {
json.Unmarshal(data, &state)
}
}
func saveState() error {
if err := os.MkdirAll(stateDir, 0755); err != nil {
return err
}
data, err := json.MarshalIndent(state, "", " ")
if err != nil {
return err
}
return os.WriteFile(stateFile, data, 0644)
}
func apiCall(method, pathName string, body interface{}) (map[string]interface{}, error) {
var reqBody io.Reader
var contentType string
if body != nil {
bodyBytes, err := json.Marshal(body)
if err != nil {
return nil, fmt.Errorf("failed to marshal request body: %w", err)
}
reqBody = bytes.NewReader(bodyBytes)
contentType = "application/json"
}
req, err := http.NewRequest(method, API+pathName, reqBody)
if err != nil {
return nil, fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Authorization", "Bearer "+apiKey)
req.Header.Set("x-extend-api-version", VERSION)
if contentType != "" {
req.Header.Set("Content-Type", contentType)
}
resp, err := client.Do(req)
if err != nil {
return nil, fmt.Errorf("request failed: %w", err)
}
defer resp.Body.Close()
respBytes, err := io.ReadAll(resp.Body)
if err != nil {
return nil, fmt.Errorf("failed to read response body: %w", err)
}
var data map[string]interface{}
json.Unmarshal(respBytes, &data)
if resp.StatusCode >= 400 {
respStr := string(respBytes)
if len(respStr) > 300 {
respStr = respStr[:300]
}
return nil, fmt.Errorf("%s %s failed (%d): %s", method, pathName, resp.StatusCode, respStr)
}
return data, nil
}
func main() {
workflow := map[string]interface{}{
"name": "Explanation of Benefits Processing Pipeline",
"steps": []map[string]interface{}{
{
"name": "startTrigger1",
"type": "TRIGGER",
"next": []map[string]interface{}{
{"step": "parse1"},
},
},
{
"name": "parse1",
"type": "PARSE",
"config": map[string]interface{}{
"parseConfig": map[string]interface{}{
"blockOptions": map[string]interface{}{
"text": map[string]interface{}{
"agentic": map[string]interface{}{
"enabled": true,
},
"signatureDetectionEnabled": true,
},
"tables": map[string]interface{}{
"agentic": map[string]interface{}{
"enabled": true,
},
"tableHeaderContinuationEnabled": true,
},
"figures": map[string]interface{}{
"enabled": true,
},
},
"chunkingStrategy": map[string]interface{}{
"type": "page",
"options": map[string]interface{}{},
},
},
},
"next": []map[string]interface{}{
{"step": "extraction2"},
},
},
{
"name": "extraction2",
"type": "EXTRACT",
"config": map[string]interface{}{
"extractorConfig": map[string]interface{}{
"schema": extractionSchema(),
"baseProcessor": "extraction_performance",
},
},
},
},
}
fmt.Printf("Deploying \"%s\"…\n", workflow["name"])
if state.WorkflowID != nil {
fmt.Printf("✓ workflow already provisioned (%s) — updating steps\n", *state.WorkflowID)
if _, err := apiCall("POST", fmt.Sprintf("/workflows/%s", *state.WorkflowID), map[string]interface{}{"steps": workflow["steps"]}); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
} else {
// Try to find an existing workflow with the same name
q := url.QueryEscape("Explanation of Benefits Processing Pipeline")
list, err := apiCall("GET", fmt.Sprintf("/workflows?name=%s", q), nil)
if err == nil {
items := []WorkflowItem{}
if data, ok := list["data"].([]interface{}); ok {
for _, v := range data {
if b, err := json.Marshal(v); err == nil {
var item WorkflowItem
if json.Unmarshal(b, &item) == nil {
items = append(items, item)
}
}
}
} else if data, ok := list["items"].([]interface{}); ok {
for _, v := range data {
if b, err := json.Marshal(v); err == nil {
var item WorkflowItem
if json.Unmarshal(b, &item) == nil {
items = append(items, item)
}
}
}
}
for _, item := range items {
if item.Name != nil && *item.Name == "Explanation of Benefits Processing Pipeline" && item.ID != nil {
state.WorkflowID = item.ID
saveState()
fmt.Printf("✓ workflow \"Explanation of Benefits Processing Pipeline\" found in your account (%s) — updating steps\n", *item.ID)
if _, err := apiCall("POST", fmt.Sprintf("/workflows/%s", *item.ID), map[string]interface{}{"steps": workflow["steps"]}); err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
printDone(state.WorkflowID)
return
}
}
}
if state.WorkflowID == nil {
created, err := apiCall("POST", "/workflows", workflow)
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
var wfID *string
if id, ok := created["id"].(string); ok {
wfID = &id
} else if wf, ok := created["workflow"].(map[string]interface{}); ok {
if id, ok := wf["id"].(string); ok {
wfID = &id
}
}
if wfID == nil {
fmt.Fprintf(os.Stderr, "Error: Could not read created workflow id from response\n")
os.Exit(1)
}
state.WorkflowID = wfID
saveState()
fmt.Printf("+ created workflow (%s)\n", *wfID)
}
}
// Best-effort: deploy the current draft as a new version
apiCall("POST", fmt.Sprintf("/workflows/%s/versions", *state.WorkflowID), map[string]interface{}{})
printDone(state.WorkflowID)
}
func printDone(wfID *string) {
fmt.Println("\nDone. Run documents through it with:")
fmt.Printf(" POST %s/workflow_runs { workflow: { id: \"%s\" }, file: { url: \"https://…\" } }\n", API, *wfID)
fmt.Println("Or open the workflow in the Extend dashboard to review and deploy it.")
}
func extractionSchema() map[string]interface{} {
return map[string]interface{}{
"type": "object",
"required": []string{
"member_id", "plan_name", "eob_number", "group_number", "patient_name",
"amount_billed", "provider_name", "amount_allowed", "date_processed",
"subscriber_name", "claim_line_items", "benefit_period_end",
"deductible_maximum", "benefit_period_start", "out_of_pocket_maximum",
"deductible_met_to_date", "patient_responsibility", "discounts_and_reductions",
"out_of_pocket_met_to_date", "health_plan_responsibility",
},
"properties": map[string]interface{}{
"member_id": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The unique identification number assigned to the insured member or subscriber. This is used by the health plan to identify the covered individual. May be labeled as 'Member ID', 'Subscriber ID', or similar.",
},
"plan_name": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The name of the health insurance plan or product under which the claim was processed. May appear as 'Plan Name', 'Product', or similar.",
},
"eob_number": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The unique identifier for this Explanation of Benefits (EOB) document or claim. This is the primary reference number used to track this EOB. May include numbers, letters, or special characters. Common labels include 'Claim #', 'EOB #', or similar.",
},
"group_number": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The group or employer number associated with the health plan. This identifies the employer or group plan under which the member is covered. Commonly labeled as 'Group #', 'Group Number', etc.",
},
"patient_name": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The full name of the individual who received the medical services. May be labeled as 'Patient', 'Covered Person', or similar.",
},
"amount_billed": currencyType("The total amount billed by the provider for all services included in this claim. This is the original charge before any discounts, reductions, or insurance adjustments."),
"provider_name": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The name of the healthcare provider, facility, or organization that rendered the services for this claim. May be labeled as 'Provider', 'Facility', or similar.",
},
"amount_allowed": currencyType("The total amount allowed by the health plan for the services provided, after discounts and reductions. This is the maximum amount considered for payment."),
"date_processed": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The date on which this claim or EOB was processed by the health plan. May be labeled as 'Date Processed', 'Processed On', or similar.",
"extend:type": "date",
},
"subscriber_name": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The name of the primary insured individual or policyholder. This is the person who holds the insurance policy, sometimes labeled as 'Subscriber', 'Participant', or 'Member'.",
},
"claim_line_items": map[string]interface{}{
"type": "array",
"items": map[string]interface{}{
"type": "object",
"required": []string{
"notes", "copay_amount", "amount_billed", "amount_allowed",
"service_end_date", "deductible_amount", "amount_not_covered",
"coinsurance_amount", "service_start_date", "service_description",
"patient_responsibility", "discounts_and_reductions", "health_plan_responsibility",
},
"properties": map[string]interface{}{
"notes": map[string]interface{}{
"type": []string{"string", "null"},
"description": "Any notes, remarks, or explanations related to this service line, such as denial reasons, bundling, or special instructions. May be referenced by footnotes or symbols.",
},
"copay_amount": map[string]interface{}{
"type": []interface{}{float64(0), nil},
"description": "The copayment amount the patient is responsible for on this service line.",
},
"amount_billed": map[string]interface{}{
"type": []interface{}{float64(0), nil},
"description": "The amount billed by the provider for this specific service line, before any discounts or reductions.",
},
"amount_allowed": map[string]interface{}{
"type": []interface{}{float64(0), nil},
"description": "The amount allowed by the health plan for this service line after discounts and reductions.",
},
"service_end_date": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The date on which the service or procedure ended, if applicable. May be omitted if service occurred on a single day.",
"extend:type": "date",
},
"deductible_amount": map[string]interface{}{
"type": []interface{}{float64(0), nil},
"description": "The portion of this service line applied to the patient's deductible.",
},
"amount_not_covered": map[string]interface{}{
"type": []interface{}{float64(0), nil},
"description": "The amount for this service line that is not covered by the health plan and is the patient's responsibility.",
},
"coinsurance_amount": map[string]interface{}{
"type": []interface{}{float64(0), nil},
"description": "The coinsurance amount the patient is responsible for on this service line.",
},
"service_start_date": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The date on which the service or procedure began or was rendered. May be labeled as 'Service Date', 'Date of Service', or similar.",
"extend:type": "date",
},
"service_description": map[string]interface{}{
"type": []string{"string", "null"},
"description": "A description of the medical service, procedure, or supply provided. May include procedure names, codes, or other identifying information.",
},
"patient_responsibility": map[string]interface{}{
"type": []interface{}{float64(0), nil},
"description": "The total amount the patient is responsible for on this service line, including deductible, copay, coinsurance, and non-covered amounts.",
},
"discounts_and_reductions": map[string]interface{}{
"type": []interface{}{float64(0), nil},
"description": "The amount of discounts, reductions, or adjustments applied to this service line by the health plan.",
},
"health_plan_responsibility": map[string]interface{}{
"type": []interface{}{float64(0), nil},
"description": "The amount paid or payable by the health plan for this service line.",
},
},
"additionalProperties": false,
},
"description": "The individual service lines or procedures included in this claim. Each item represents a specific service, procedure, or charge, and includes details about dates, amounts, and benefit application. Format and labeling may vary widely across EOBs.",
},
"benefit_period_end": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The end date of the benefit period relevant to this EOB or claim. This is the end of the coverage period for deductibles and out-of-pocket calculations.",
"extend:type": "date",
},
"deductible_maximum": currencyType("The total deductible maximum for the benefit period for the patient or family, as specified by the plan."),
"benefit_period_start": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The start date of the benefit period relevant to this EOB or claim. This is the beginning of the coverage period for deductibles and out-of-pocket calculations.",
"extend:type": "date",
},
"out_of_pocket_maximum": currencyType("The total out-of-pocket maximum for the benefit period for the patient or family, as specified by the plan."),
"deductible_met_to_date": currencyType("The cumulative amount of deductible met by the patient for the current benefit period as of this EOB. This reflects progress toward the annual deductible."),
"patient_responsibility": currencyType("The total amount the patient may owe to the provider for these services, after insurance payments and adjustments. This may include deductibles, copays, coinsurance, and non-covered amounts."),
"discounts_and_reductions": currencyType("The total amount of discounts, reductions, or adjustments applied to the billed charges by the health plan. This may include network discounts, negotiated rates, or other reductions."),
"out_of_pocket_met_to_date": currencyType("The cumulative amount of out-of-pocket expenses met by the patient for the current benefit period as of this EOB. This includes deductibles, copays, and coinsurance."),
"health_plan_responsibility": currencyType("The total amount paid or payable by the health plan for this claim. This is the insurer's share of the allowed amount."),
},
"additionalProperties": false,
}
}
func currencyType(description string) map[string]interface{} {
return map[string]interface{}{
"type": "object",
"required": []string{"amount", "iso_4217_currency_code"},
"properties": map[string]interface{}{
"amount": map[string]interface{}{
"type": []interface{}{float64(0), nil},
},
"iso_4217_currency_code": map[string]interface{}{
"type": []string{"string", "null"},
},
},
"description": description,
"extend:type": "currency",
"additionalProperties": false,
}
}An Explanation of Benefits (EOB) shows how an insurance claim was processed, including charges, coverage applied, and what the patient may owe. This extractor captures claim, member, subscriber, patient, provider, financial total, benefit-period, deductible/out-of-pocket, and service-line details. It is optimized for higher extraction accuracy and reviewability. Fine-tuning can be done through extractor settings, citations, array strategy, chunking, merge strategy, extraction rules, and parser configuration.