Extracts claim details, injury descriptions, and financial summaries from workers' compensation claims.
A claim summary is a loss run report issued by an insurance carrier that documents all active and closed injury claims, including claimant details, injury circumstances, claim status indicators, and financial summaries broken down by indemnity, medical, and expense categories. This template takes in loss run claim summaries and outputs markdown (.md) capturing the document's full text and layout, and JSON (.json) with structured claim fields including employee information, injury dates, claim status flags, financial totals by category, and report metadata per the extraction schema by using Extend's Parse, Extract primitives.
Parse workers' compensation claim summary to markdown
blockOptions.text.agentic.enabledtruechangedchunkingStrategy.type"document"engine"parse_performance"You can learn more about Parse configuration in Extend's Parse documentation.
Extract workers' compensation claim summary fields
schemacustom schema — 5 fieldschangedadvancedOptions.advancedMultimodalEnabledtruechangedadvancedOptions.reviewAgent.enabledtruechangedbaseProcessor"extraction_performance"You can learn more about Extract configuration in Extend's Extract documentation.
{
"name": "Workers' Compensation Claim Summary Processing Pipeline",
"steps": [
{
"name": "startTrigger1",
"type": "TRIGGER",
"next": [
{
"step": "parse1"
}
]
},
{
"name": "parse1",
"type": "PARSE",
"config": {
"parseConfig": {
"blockOptions": {
"text": {
"agentic": {
"enabled": true
}
}
},
"chunkingStrategy": {
"type": "document"
}
}
},
"next": [
{
"step": "extraction2"
}
]
},
{
"name": "extraction2",
"type": "EXTRACT",
"config": {
"extractorConfig": {
"schema": {
"type": "object",
"required": [
"claims",
"program",
"employer",
"date_printed",
"valued_as_of"
],
"properties": {
"claims": {
"type": "array",
"items": {
"type": "object",
"required": [
"sdtf",
"status",
"surgery",
"adjuster",
"litigated",
"longshore",
"voc_rehab",
"claim_type",
"controvert",
"date_hired",
"financials",
"fraudulent",
"occupation",
"settlement",
"subrogated",
"case_manager",
"claim_number",
"employee_ssn",
"jurisdiction",
"employee_name",
"date_of_injury",
"emp_report_date",
"carrier_entry_date",
"carrier_notify_date",
"accident_description"
],
"properties": {
"sdtf": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary."
},
"status": {
"type": [
"string",
"null"
],
"description": "The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'."
},
"surgery": {
"type": [
"string",
"null"
],
"description": "Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary."
},
"adjuster": {
"type": [
"string",
"null"
],
"description": "The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'."
},
"litigated": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary."
},
"longshore": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary."
},
"voc_rehab": {
"type": [
"string",
"null"
],
"description": "Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary."
},
"claim_type": {
"type": [
"string",
"null"
],
"description": "The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'."
},
"controvert": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary."
},
"date_hired": {
"type": [
"string",
"null"
],
"description": "The date the employee was hired by the employer. May be labeled as 'Date Hired'.",
"extend:type": "date"
},
"financials": {
"type": "object",
"required": [
"total",
"expense",
"medical",
"indemnity"
],
"properties": {
"total": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month"
],
"properties": {
"payments": {
"type": [
"number",
"null"
],
"description": "The total payments made to date on this claim."
},
"recovery": {
"type": [
"number",
"null"
],
"description": "The total amount recovered on this claim."
},
"reserves": {
"type": [
"number",
"null"
],
"description": "The total amount reserved for this claim."
},
"net_incurred": {
"type": [
"number",
"null"
],
"description": "The total net incurred amount for this claim (reserves plus payments minus recoveries)."
},
"paid_this_month": {
"type": [
"number",
"null"
],
"description": "The total amount paid during the current month."
},
"incurred_this_month": {
"type": [
"number",
"null"
],
"description": "The total amount incurred during the current month."
}
},
"description": "Total financials for this claim, summing indemnity, medical, and expense categories.",
"additionalProperties": false
},
"expense": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month"
],
"properties": {
"payments": {
"type": [
"number",
"null"
],
"description": "The total expense payments made to date on this claim."
},
"recovery": {
"type": [
"number",
"null"
],
"description": "The amount recovered for expenses on this claim."
},
"reserves": {
"type": [
"number",
"null"
],
"description": "The amount reserved for expenses on this claim."
},
"net_incurred": {
"type": [
"number",
"null"
],
"description": "The net incurred expense amount (reserves plus payments minus recoveries)."
},
"paid_this_month": {
"type": [
"number",
"null"
],
"description": "The expense amount paid during the current month."
},
"incurred_this_month": {
"type": [
"number",
"null"
],
"description": "The expense amount incurred during the current month."
}
},
"description": "Financial details for the expense portion of the claim.",
"additionalProperties": false
},
"medical": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month"
],
"properties": {
"payments": {
"type": [
"number",
"null"
],
"description": "The total medical payments made to date on this claim."
},
"recovery": {
"type": [
"number",
"null"
],
"description": "The amount recovered for medical on this claim."
},
"reserves": {
"type": [
"number",
"null"
],
"description": "The amount reserved for medical payments on this claim."
},
"net_incurred": {
"type": [
"number",
"null"
],
"description": "The net incurred medical amount (reserves plus payments minus recoveries)."
},
"paid_this_month": {
"type": [
"number",
"null"
],
"description": "The medical amount paid during the current month."
},
"incurred_this_month": {
"type": [
"number",
"null"
],
"description": "The medical amount incurred during the current month."
}
},
"description": "Financial details for the medical portion of the claim.",
"additionalProperties": false
},
"indemnity": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month"
],
"properties": {
"payments": {
"type": [
"number",
"null"
],
"description": "The total indemnity payments made to date on this claim."
},
"recovery": {
"type": [
"number",
"null"
],
"description": "The amount recovered for indemnity on this claim."
},
"reserves": {
"type": [
"number",
"null"
],
"description": "The amount reserved for indemnity payments on this claim."
},
"net_incurred": {
"type": [
"number",
"null"
],
"description": "The net incurred indemnity amount (reserves plus payments minus recoveries)."
},
"paid_this_month": {
"type": [
"number",
"null"
],
"description": "The indemnity amount paid during the current month."
},
"incurred_this_month": {
"type": [
"number",
"null"
],
"description": "The indemnity amount incurred during the current month."
}
},
"description": "Financial details for indemnity (wage replacement) portion of the claim.",
"additionalProperties": false
}
},
"description": "Summary of financial amounts associated with this claim, broken down by category such as indemnity, medical, and expense. Amounts may be shown as reserves, payments, recoveries, net incurred, and monthly values.",
"additionalProperties": false
},
"fraudulent": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary."
},
"occupation": {
"type": [
"string",
"null"
],
"description": "The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'."
},
"settlement": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary."
},
"subrogated": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary."
},
"case_manager": {
"type": [
"string",
"null"
],
"description": "The name or identifier of the case manager handling this claim, if applicable."
},
"claim_number": {
"type": [
"string",
"null"
],
"description": "The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value."
},
"employee_ssn": {
"type": [
"string",
"null"
],
"description": "The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy."
},
"jurisdiction": {
"type": [
"string",
"null"
],
"description": "The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'."
},
"employee_name": {
"type": [
"string",
"null"
],
"description": "The name of the employee or claimant associated with this claim. May be labeled as 'Employee'."
},
"date_of_injury": {
"type": [
"string",
"null"
],
"description": "The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar.",
"extend:type": "date"
},
"emp_report_date": {
"type": [
"string",
"null"
],
"description": "The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar.",
"extend:type": "date"
},
"carrier_entry_date": {
"type": [
"string",
"null"
],
"description": "The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'.",
"extend:type": "date"
},
"carrier_notify_date": {
"type": [
"string",
"null"
],
"description": "The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'.",
"extend:type": "date"
},
"accident_description": {
"type": [
"string",
"null"
],
"description": "A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where."
}
},
"additionalProperties": false
},
"description": "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats."
},
"program": {
"type": [
"string",
"null"
],
"description": "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions."
},
"employer": {
"type": [
"string",
"null"
],
"description": "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy."
},
"date_printed": {
"type": [
"string",
"null"
],
"description": "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.",
"extend:type": "date"
},
"valued_as_of": {
"type": [
"string",
"null"
],
"description": "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.",
"extend:type": "date"
}
},
"additionalProperties": false
},
"baseProcessor": "extraction_performance",
"advancedOptions": {
"reviewAgent": {
"enabled": true
},
"advancedMultimodalEnabled": true
}
}
}
}
]
}# Workers' Compensation Claim Summary Processing — Extend AI Skill
## What this pipeline does
This pipeline ingests Workers' Compensation Claim Summary documents (typically multi-page loss run reports) and extracts structured claim data including employee details, injury dates, claim status flags, and detailed financial breakdowns by category (medical, indemnity, expense). It uses agentic OCR to handle complex table layouts and embedded claim data, then extracts into a nested JSON schema with per-claim financials and document-level metadata.
## When to use this
- **Loss run ingestion**: Automatically parse carrier-issued loss run reports into normalized JSON for downstream claim management systems.
- **Bulk claim data import**: Process monthly or quarterly loss run snapshots to populate claims databases with current reserves, payments, and incurred amounts.
- **Claims analytics & reporting**: Extract structured financial data to feed BI dashboards, actuarial analyses, or compliance audits.
- **Litigation/settlement tracking**: Capture claim status flags (litigated, settled, controverted, fraudulent) for case management and reserves forecasting.
- **Multi-jurisdiction consolidation**: Handle loss runs from different states/jurisdictions and normalize claim and financial data into a single schema.
## Processor pipeline
### Step 1: Parse with agentic OCR
**Processor**: `parse_performance` with agentic text extraction enabled
**Purpose**: Convert PDF (often scanned or mixed-format) into clean markdown preserving table structure and claim boundaries
**Key config**:
- `engine: "parse_performance"` — higher-fidelity parsing for complex, multi-section documents
- `blockOptions.text.agentic.enabled: true` — enables LLM-assisted OCR for handwriting, degraded scans, and non-standard layouts
- `chunkingStrategy.type: "document"` — keeps entire loss run as one logical chunk (critical for table context)
**Why**: Loss run reports mix structured tables with narrative descriptions and status flags. Agentic OCR handles scanned carrier documents, watermarks, and irregular column alignment that pure CV-based parsing fails on. Document-level chunking preserves claim groupings and financial rollups.
### Step 2: Extract structured fields
**Processor**: `extraction_performance` with review agent enabled
**Purpose**: Parse markdown into nested JSON schema capturing claim-level and document-level metadata, with per-category financials
**Key config**:
- `baseProcessor: "extraction_performance"` — production-grade extraction with internal validation
- `advancedOptions.reviewAgent.enabled: true` — LLM verifies extracted numbers and flags (e.g., "Y"/"N" fields), catches numeric formatting issues
- `advancedOptions.advancedMultimodalEnabled: true` — leverages parsed layout info for table cell association
**Why**: The schema is deep (4-level nesting: document → claims array → claim → financials → {total, medical, indemnity, expense} objects). Review agent catches common errors: misaligned reserve/payment columns, swapped medical/indemnity subtotals, dates in unexpected formats. Advanced multimodal uses visual bounding boxes from parse step to correctly align table values.
---
## TypeScript implementation
---
## CLI equivalent
```bash
# Step 1: Parse loss run to markdown
extend parse loss_run_sample.pdf
# Step 2: Extract structured claim data using the schema
extend extract loss_run_sample.pdf \
--schema wc-claims-schema.json \
--processor extraction_performance
# Or run the pre-configured workflow (if saved in your Extend account)
extend run workflow_wc_claim_summary \
--file loss_run_sample.pdf
```
Where `wc-claims-schema.json` is the full extraction schema (see Schema section below).
---
## Schema
```json
{
"type": "object",
"properties": {
"employer": {
"type": ["string", "null"],
"description": "Name of employer or insured organization. This is the entity covered by the workers' compensation policy."
},
"program": {
"type": ["string", "null"],
"description": "Insurance program, policy, or coverage type. May be a program name, code, or description of the coverage structure."
},
"date_printed": {
"type": ["string", "null"],
"extend:type": "date",
"description": "Report generation or print date (ISO yyyy-mm-dd format). This is the official date of the loss run document."
},
"valued_as_of": {
"type": ["string", "null"],
"extend:type": "date",
"description": "Valuation date for all financial figures in the report (ISO yyyy-mm-dd). All reserves, payments, and incimport fs from "fs";
import { ExtendClient, extendDate, extendCurrency } from "extend-ai";
import { z } from "zod";
/**
* Zod schema for Workers' Compensation Claim Summary extraction.
* Mirrors the nested structure: document metadata + array of claims with financials.
*/
const claimFinancialsSchema = z.object({
payments: z.number().nullable().describe("Total payments made to date"),
recovery: z.number().nullable().describe("Total amount recovered"),
reserves: z.number().nullable().describe("Total amount reserved"),
net_incurred: z.number().nullable().describe("Net incurred (reserves + payments - recoveries)"),
paid_this_month: z.number().nullable().describe("Amount paid this month"),
incurred_this_month: z.number().nullable().describe("Amount incurred this month"),
});
const claimSchema = z.object({
// Identifiers
claim_number: z.string().nullable().describe("Unique claim identifier (e.g., 'CLM-2024-001234')"),
employee_name: z.string().nullable().describe("Name of the injured worker"),
employee_ssn: z.string().nullable().describe("Social Security Number (may be redacted)"),
// Dates
date_of_injury: extendDate().describe("Date of injury incident (ISO yyyy-mm-dd)"),
emp_report_date: extendDate().describe("Date employee reported the injury"),
carrier_notify_date: extendDate().describe("Date insurance carrier was notified"),
carrier_entry_date: extendDate().describe("Date claim was entered into carrier system"),
date_hired: extendDate().describe("Employee hire date"),
// Claim details
occupation: z.string().nullable().describe("Job title at time of injury"),
jurisdiction: z.string().nullable().describe("State/jurisdiction where claim is filed"),
claim_type: z.string().nullable().describe("Claim type (e.g., 'Medical Only', 'Indemnity', 'Lost Time')"),
status: z.string().nullable().describe("Current status (e.g., 'Open', 'Closed')"),
accident_description: z.string().nullable().describe("Narrative description of the accident or injury"),
// Status flags (typically Y/N)
surgery: z.string().nullable().describe("Surgery performed? (Y/N or similar)"),
litigated: z.string().nullable().describe("Claim in litigation? (Y/N)"),
settled: z.string().nullable().describe("Claim settled? (Y/N)"),
controvert: z.string().nullable().describe("Claim controverted/disputed? (Y/N)"),
voc_rehab: z.string().nullable().describe("Vocational rehabilitation provided? (Y/N)"),
subrogated: z.string().nullable().describe("Claim subrogated? (Y/N)"),
fraudulent: z.string().nullable().describe("Suspected/confirmed fraud? (Y/N)"),
sdtf: z.string().nullable().describe("Subject to Second Disability Trust Fund? (Y/N)"),
longshore: z.string().nullable().describe("Subject to LHWCA or similar? (Y/N)"),
// Personnel
adjuster: z.string().nullable().describe("Assigned claims adjuster name or ID"),
case_manager: z.string().nullable().describe("Case manager name or ID, if applicable"),
// Financials: broken down by category (medical, indemnity, expense) plus total
financials: z.object({
total: claimFinancialsSchema.describe("Total across all categories"),
medical: claimFinancialsSchema.describe("Medical portion only"),
indemnity: claimFinancialsSchema.describe("Indemnity (wage replacement) portion only"),
expense: claimFinancialsSchema.describe("Expenses portion only"),
}).describe("Financial summary: reserves, payments, recoveries, net incurred, and monthly values by category"),
});
const lossRunSchema = z.object({
employer: z.string().nullable().describe("Name of employer/insured organization"),
program: z.string().nullable().describe("Insurance program or coverage type"),
date_printed: extendDate().describe("Report generation/print date (ISO yyyy-mm-dd)"),
valued_as_of: extendDate().describe("Valuation date for all amounts in the report (ISO yyyy-mm-dd)"),
claims: z.array(claimSchema).describe("Array of individual claims in this loss run"),
});
/**
* Process a Workers' Compensation Claim Summary loss run document.
* Uploads the file, parses it with agentic OCR, then extracts structured claim data.
* @param filePath Path to local loss run PDF file
*/
async function processWorkersCompensationClaimSummary(filePath: string) {
const client = new ExtendClient({ token: process.env.EXTEND_API_KEY });
console.log(`[WC Loss Run] Processing: ${filePath}`);
// Convert local file to data URL (base64)
const fileBuffer = fs.readFileSync(filePath);
const base64 = fileBuffer.toString("base64");
const dataUrl = `data:application/pdf;base64,${base64}`;
// Step 1: Parse the loss run with agentic OCR
console.log("[Step 1/2] Parsing loss run with agentic OCR...");
const parseRun = await client.parseRuns.createAndPoll({
file: { url: dataUrl },
config: {
mode: "agentic_ocr", // Scanned, handwritten, or complex table layouts
outputType: "markdown",
},
});
if (parseRun.status !== "PROCESSED") {
throw new Error(`Parse failed with status: ${parseRun.status}`);
}
const parsedMarkdown = parseRun.output.chunks
.map((chunk) => chunk.content)
.join("\n\n");
console.log(
`[Step 1/2] Parsed ${parseRun.output.chunks.length} chunks. ` +
`Markdown length: ${parsedMarkdown.length} characters.`
);
// Step 2: Extract structured claim data
console.log("[Step 2/2] Extracting structured claim data...");
const extractRun = await client.extractRuns.createAndPoll({
file: { url: dataUrl },
config: {
schema: lossRunSchema,
baseProcessor: "extraction_performance", // Production-grade extraction
},
});
if (extractRun.status !== "PROCESSED") {
throw new Error(`Extraction failed with status: ${extractRun.status}`);
}
const lossRunData = extractRun.output.value;
console.log(`[Step 2/2] Extraction complete.`);
console.log(`Employer: ${lossRunData.employer}`);
console.log(`Program: ${lossRunData.program}`);
console.log(`Report Date: ${lossRunData.date_printed}`);
console.log(`Valued As Of: ${lossRunData.valued_as_of}`);
console.log(`Total Claims: ${lossRunData.claims.length}`);
// Example: Print first claim summary (if any)
if (lossRunData.claims.length > 0) {
const firstClaim = lossRunData.claims[0];
console.log(`\n[Sample Claim #1]`);
console.log(` Claim #: ${firstClaim.claim_number}`);
console.log(` Employee: ${firstClaim.employee_name}`);
console.log(` DOI: ${firstClaim.date_of_injury}`);
console.log(` Status: ${firstClaim.status}`);
console.log(` Total Net Incurred: $${firstClaim.financials.total.net_incurred?.toFixed(2) ?? "N/A"}`);
}
// Return full structured data for downstream processing
return {
status: "success",
document: {
employer: lossRunData.employer,
program: lossRunData.program,
dateReported: lossRunData.date_printed,
valuedAsOf: lossRunData.valued_as_of,
},
claims: lossRunData.claims.map((claim) => ({
claimNumber: claim.claim_number,
employeeName: claim.employee_name,
employeeSSN: claim.employee_ssn,
dateOfInjury: claim.date_of_injury,
occupation: claim.occupation,
jurisdiction: claim.jurisdiction,
claimType: claim.claim_type,
status: claim.status,
accidentDescription: claim.accident_description,
flags: {
surgery: claim.surgery,
litigated: claim.litigated,
settled: claim.settled,
controverted: claim.controvert,
vocRehab: claim.voc_rehab,
subrogated: claim.subrogated,
fraudulent: claim.fraudulent,
sdtf: claim.sdtf,
longshore: claim.longshore,
},
personnel: {
adjuster: claim.adjuster,
caseManager: claim.case_manager,
},
financials: {
total: {
payments: claim.financials.total.payments,
recovery: claim.financials.total.recovery,
reserves: claim.financials.total.reserves,
netIncurred: claim.financials.total.net_incurred,
paidThisMonth: claim.financials.total.paid_this_month,
incurredThisMonth: claim.financials.total.incurred_this_month,
},
medical: {
payments: claim.financials.medical.payments,
recovery: claim.financials.medical.recovery,
reserves: claim.financials.medical.reserves,
netIncurred: claim.financials.medical.net_incurred,
paidThisMonth: claim.financials.medical.paid_this_month,
incurredThisMonth: claim.financials.medical.incurred_this_month,
},
indemnity: {
payments: claim.financials.indemnity.payments,
recovery: claim.financials.indemnity.recovery,
reserves: claim.financials.indemnity.reserves,
netIncurred: claim.financials.indemnity.net_incurred,
paidThisMonth: claim.financials.indemnity.paid_this_month,
incurredThisMonth: claim.financials.indemnity.incurred_this_month,
},
expense: {
payments: claim.financials.expense.payments,
recovery: claim.financials.expense.recovery,
reserves: claim.financials.expense.reserves,
netIncurred: claim.financials.expense.net_incurred,
paidThisMonth: claim.financials.expense.paid_this_month,
incurredThisMonth: claim.financials.expense.incurred_this_month,
},
},
})),
rawMarkdown: parsedMarkdown, // Useful for debugging or RAG
};
}
// Auto-invoke if run directly
const filePath = process.argv[2] || "__FILE_PATH__";
processWorkersCompensationClaimSummary(filePath)
.then((result) => {
console.log("\n=== EXTRACTION RESULT ===");
console.log(JSON.stringify(result, null, 2));
})
.catch((error) => {
console.error("Error:", error.message);
process.exit(1);
});import os
import json
from typing import Optional
from extend_ai import Extend
from pydantic import BaseModel, Field
# Define nested financial schema
class ClaimFinancials(BaseModel):
payments: Optional[float] = Field(None, description="Total payments made to date")
recovery: Optional[float] = Field(None, description="Total amount recovered")
reserves: Optional[float] = Field(None, description="Total amount reserved")
net_incurred: Optional[float] = Field(None, description="Net incurred (reserves + payments - recoveries)")
paid_this_month: Optional[float] = Field(None, description="Amount paid this month")
incurred_this_month: Optional[float] = Field(None, description="Amount incurred this month")
# Define claim schema
class Claim(BaseModel):
# Identifiers
claim_number: Optional[str] = Field(None, description="Unique claim identifier (e.g., 'CLM-2024-001234')")
employee_name: Optional[str] = Field(None, description="Name of the injured worker")
employee_ssn: Optional[str] = Field(None, description="Social Security Number (may be redacted)")
# Dates
date_of_injury: Optional[str] = Field(None, description="Date of injury incident (ISO yyyy-mm-dd)")
emp_report_date: Optional[str] = Field(None, description="Date employee reported the injury")
carrier_notify_date: Optional[str] = Field(None, description="Date insurance carrier was notified")
carrier_entry_date: Optional[str] = Field(None, description="Date claim was entered into carrier system")
date_hired: Optional[str] = Field(None, description="Employee hire date")
# Claim details
occupation: Optional[str] = Field(None, description="Job title at time of injury")
jurisdiction: Optional[str] = Field(None, description="State/jurisdiction where claim is filed")
claim_type: Optional[str] = Field(None, description="Claim type (e.g., 'Medical Only', 'Indemnity', 'Lost Time')")
status: Optional[str] = Field(None, description="Current status (e.g., 'Open', 'Closed')")
accident_description: Optional[str] = Field(None, description="Narrative description of the accident or injury")
# Status flags
surgery: Optional[str] = Field(None, description="Surgery performed? (Y/N or similar)")
litigated: Optional[str] = Field(None, description="Claim in litigation? (Y/N)")
settlement: Optional[str] = Field(None, description="Claim settled? (Y/N)")
controvert: Optional[str] = Field(None, description="Claim controverted/disputed? (Y/N)")
voc_rehab: Optional[str] = Field(None, description="Vocational rehabilitation provided? (Y/N)")
subrogated: Optional[str] = Field(None, description="Claim subrogated? (Y/N)")
fraudulent: Optional[str] = Field(None, description="Suspected/confirmed fraud? (Y/N)")
sdtf: Optional[str] = Field(None, description="Subject to Second Disability Trust Fund? (Y/N)")
longshore: Optional[str] = Field(None, description="Subject to LHWCA or similar? (Y/N)")
# Personnel
adjuster: Optional[str] = Field(None, description="Assigned claims adjuster name or ID")
case_manager: Optional[str] = Field(None, description="Case manager name or ID, if applicable")
# Financials
class FinancialsNested(BaseModel):
total: ClaimFinancials = Field(description="Total across all categories")
medical: ClaimFinancials = Field(description="Medical portion only")
indemnity: ClaimFinancials = Field(description="Indemnity (wage replacement) portion only")
expense: ClaimFinancials = Field(description="Expenses portion only")
financials: FinancialsNested = Field(description="Financial summary: reserves, payments, recoveries, net incurred, and monthly values by category")
# Define loss run schema
class LossRun(BaseModel):
employer: Optional[str] = Field(None, description="Name of employer/insured organization")
program: Optional[str] = Field(None, description="Insurance program or coverage type")
date_printed: Optional[str] = Field(None, description="Report generation/print date (ISO yyyy-mm-dd)")
valued_as_of: Optional[str] = Field(None, description="Valuation date for all amounts in the report (ISO yyyy-mm-dd)")
claims: list[Claim] = Field(description="Array of individual claims in this loss run")
def process_workers_compensation_claim_summary(file_path: str) -> dict:
"""
Process a Workers' Compensation Claim Summary loss run document.
Uploads the file, parses it with agentic OCR, then extracts structured claim data.
Args:
file_path: Path to local loss run PDF file
Returns:
Dictionary containing extracted structured data
"""
client = Extend(token=os.getenv("EXTEND_API_KEY"))
print(f"[WC Loss Run] Processing: {file_path}")
# Convert local file to data URL (base64)
with open(file_path, "rb") as f:
file_buffer = f.read()
base64_str = __import__("base64").b64encode(file_buffer).decode("utf-8")
data_url = f"data:application/pdf;base64,{base64_str}"
# Step 1: Parse the loss run with agentic OCR
print("[Step 1/2] Parsing loss run with agentic OCR...")
parse_run = client.parse_runs.create_and_poll(
file={"url": data_url},
config={
"mode": "agentic_ocr",
"output_type": "markdown",
}
)
if parse_run.status != "PROCESSED":
raise Exception(f"Parse failed with status: {parse_run.status}")
parsed_markdown = "\n\n".join(chunk.content for chunk in parse_run.output.chunks)
print(
f"[Step 1/2] Parsed {len(parse_run.output.chunks)} chunks. "
f"Markdown length: {len(parsed_markdown)} characters."
)
# Step 2: Extract structured claim data
print("[Step 2/2] Extracting structured claim data...")
extract_run = client.extract_runs.create_and_poll(
file={"url": data_url},
config={
"schema": LossRun,
"base_processor": "extraction_performance",
}
)
if extract_run.status != "PROCESSED":
raise Exception(f"Extraction failed with status: {extract_run.status}")
loss_run_data = extract_run.output.value
print("[Step 2/2] Extraction complete.")
print(f"Employer: {loss_run_data.employer}")
print(f"Program: {loss_run_data.program}")
print(f"Report Date: {loss_run_data.date_printed}")
print(f"Valued As Of: {loss_run_data.valued_as_of}")
print(f"Total Claims: {len(loss_run_data.claims)}")
# Example: Print first claim summary (if any)
if loss_run_data.claims:
first_claim = loss_run_data.claims[0]
print(f"\n[Sample Claim #1]")
print(f" Claim #: {first_claim.claim_number}")
print(f" Employee: {first_claim.employee_name}")
print(f" DOI: {first_claim.date_of_injury}")
print(f" Status: {first_claim.status}")
net_incurred = first_claim.financials.total.net_incurred
print(f" Total Net Incurred: ${net_incurred:.2f if net_incurred else 'N/A'}")
# Return full structured data for downstream processing
return {
"status": "success",
"document": {
"employer": loss_run_data.employer,
"program": loss_run_data.program,
"date_reported": loss_run_data.date_printed,
"valued_as_of": loss_run_data.valued_as_of,
},
"claims": [
{
"claim_number": claim.claim_number,
"employee_name": claim.employee_name,
"employee_ssn": claim.employee_ssn,
"date_of_injury": claim.date_of_injury,
"occupation": claim.occupation,
"jurisdiction": claim.jurisdiction,
"claim_type": claim.claim_type,
"status": claim.status,
"accident_description": claim.accident_description,
"flags": {
"surgery": claim.surgery,
"litigated": claim.litigated,
"settled": claim.settlement,
"controverted": claim.controvert,
"voc_rehab": claim.voc_rehab,
"subrogated": claim.subrogated,
"fraudulent": claim.fraudulent,
"sdtf": claim.sdtf,
"longshore": claim.longshore,
},
"personnel": {
"adjuster": claim.adjuster,
"case_manager": claim.case_manager,
},
"financials": {
"total": {
"payments": claim.financials.total.payments,
"recovery": claim.financials.total.recovery,
"reserves": claim.financials.total.reserves,
"net_incurred": claim.financials.total.net_incurred,
"paid_this_month": claim.financials.total.paid_this_month,
"incurred_this_month": claim.financials.total.incurred_this_month,
},
"medical": {
"payments": claim.financials.medical.payments,
"recovery": claim.financials.medical.recovery,
"reserves": claim.financials.medical.reserves,
"net_incurred": claim.financials.medical.net_incurred,
"paid_this_month": claim.financials.medical.paid_this_month,
"incurred_this_month": claim.financials.medical.incurred_this_month,
},
"indemnity": {
"payments": claim.financials.indemnity.payments,
"recovery": claim.financials.indemnity.recovery,
"reserves": claim.financials.indemnity.reserves,
"net_incurred": claim.financials.indemnity.net_incurred,
"paid_this_month": claim.financials.indemnity.paid_this_month,
"incurred_this_month": claim.financials.indemnity.incurred_this_month,
},
"expense": {
"payments": claim.financials.expense.payments,
"recovery": claim.financials.expense.recovery,
"reserves": claim.financials.expense.reserves,
"net_incurred": claim.financials.expense.net_incurred,
"paid_this_month": claim.financials.expense.paid_this_month,
"incurred_this_month": claim.financials.expense.incurred_this_month,
},
},
}
for claim in loss_run_data.claims
],
"raw_markdown": parsed_markdown,
}
# Auto-invoke if run directly
if __name__ == "__main__":
import sys
file_path = sys.argv[1] if len(sys.argv) > 1 else "__FILE_PATH__"
try:
result = process_workers_compensation_claim_summary(file_path)
print("\n=== EXTRACTION RESULT ===")
print(json.dumps(result, indent=2))
except Exception as e:
print(f"Error: {str(e)}", file=sys.stderr)
sys.exit(1)import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.extend.client.ExtendClient;
import com.extend.client.models.ExtractRunRequest;
import com.extend.client.models.ExtractRunResult;
import com.extend.client.models.ParseRunRequest;
import com.extend.client.models.ParseRunResult;
import com.extend.client.models.FileInput;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* Process a Workers' Compensation Claim Summary loss run document.
* Uploads the file, parses it with agentic OCR, then extracts structured claim data.
*/
public class WorkersCompensationClaimSummaryProcessor {
private static final ObjectMapper objectMapper = new ObjectMapper();
public static void main(String[] args) throws IOException {
String filePath = args.length > 0 ? args[0] : "__FILE_PATH__";
try {
Map<String, Object> result = processWorkersCompensationClaimSummary(filePath);
System.out.println("\n=== EXTRACTION RESULT ===");
System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(result));
} catch (Exception e) {
System.err.println("Error: " + e.getMessage());
System.exit(1);
}
}
public static Map<String, Object> processWorkersCompensationClaimSummary(String filePath)
throws IOException, InterruptedException {
String apiKey = System.getenv("EXTEND_API_KEY");
ExtendClient client = new ExtendClient.Builder().token(apiKey).build();
System.out.println("[WC Loss Run] Processing: " + filePath);
// Convert local file to data URL (base64)
byte[] fileBuffer = Files.readAllBytes(Paths.get(filePath));
String base64 = Base64.getEncoder().encodeToString(fileBuffer);
String dataUrl = "data:application/pdf;base64," + base64;
// Step 1: Parse the loss run with agentic OCR
System.out.println("[Step 1/2] Parsing loss run with agentic OCR...");
ParseRunRequest parseRequest = ParseRunRequest.builder()
.file(new FileInput(dataUrl))
.mode("agentic_ocr")
.outputType("markdown")
.build();
ParseRunResult parseRun = client.parseRuns().createAndPoll(parseRequest);
if (!"PROCESSED".equals(parseRun.getStatus())) {
throw new RuntimeException("Parse failed with status: " + parseRun.getStatus());
}
StringBuilder parsedMarkdown = new StringBuilder();
int chunkCount = parseRun.getOutput().getChunks().size();
for (Map<String, Object> chunk : parseRun.getOutput().getChunks()) {
if (parsedMarkdown.length() > 0) {
parsedMarkdown.append("\n\n");
}
parsedMarkdown.append(chunk.get("content"));
}
System.out.println("[Step 1/2] Parsed " + chunkCount + " chunks. " +
"Markdown length: " + parsedMarkdown.length() + " characters.");
// Step 2: Extract structured claim data
System.out.println("[Step 2/2] Extracting structured claim data...");
Map<String, Object> schemaMap = buildLossRunSchema();
ExtractRunRequest extractRequest = ExtractRunRequest.builder()
.file(new FileInput(dataUrl))
.schema(schemaMap)
.baseProcessor("extraction_performance")
.build();
ExtractRunResult extractRun = client.extractRuns().createAndPoll(extractRequest);
if (!"PROCESSED".equals(extractRun.getStatus())) {
throw new RuntimeException("Extraction failed with status: " + extractRun.getStatus());
}
Map<String, Object> lossRunData = (Map<String, Object>) extractRun.getOutput().getValue();
System.out.println("[Step 2/2] Extraction complete.");
System.out.println("Employer: " + lossRunData.get("employer"));
System.out.println("Program: " + lossRunData.get("program"));
System.out.println("Report Date: " + lossRunData.get("date_printed"));
System.out.println("Valued As Of: " + lossRunData.get("valued_as_of"));
List<Map<String, Object>> claims = (List<Map<String, Object>>) lossRunData.get("claims");
System.out.println("Total Claims: " + claims.size());
// Example: Print first claim summary (if any)
if (!claims.isEmpty()) {
Map<String, Object> firstClaim = claims.get(0);
System.out.println("\n[Sample Claim #1]");
System.out.println(" Claim #: " + firstClaim.get("claim_number"));
System.out.println(" Employee: " + firstClaim.get("employee_name"));
System.out.println(" DOI: " + firstClaim.get("date_of_injury"));
System.out.println(" Status: " + firstClaim.get("status"));
Map<String, Object> financials = (Map<String, Object>) firstClaim.get("financials");
Map<String, Object> total = (Map<String, Object>) financials.get("total");
Object netIncurred = total.get("net_incurred");
String netIncurredStr = netIncurred != null ? String.format("%.2f", netIncurred) : "N/A";
System.out.println(" Total Net Incurred: $" + netIncurredStr);
}
// Build return structure
Map<String, Object> document = new HashMap<>();
document.put("employer", lossRunData.get("employer"));
document.put("program", lossRunData.get("program"));
document.put("dateReported", lossRunData.get("date_printed"));
document.put("valuedAsOf", lossRunData.get("valued_as_of"));
List<Map<String, Object>> processedClaims = new ArrayList<>();
for (Map<String, Object> claim : claims) {
processedClaims.add(transformClaim(claim));
}
Map<String, Object> result = new HashMap<>();
result.put("status", "success");
result.put("document", document);
result.put("claims", processedClaims);
result.put("rawMarkdown", parsedMarkdown.toString());
return result;
}
private static Map<String, Object> transformClaim(Map<String, Object> claim) {
Map<String, Object> transformed = new HashMap<>();
transformed.put("claimNumber", claim.get("claim_number"));
transformed.put("employeeName", claim.get("employee_name"));
transformed.put("employeeSSN", claim.get("employee_ssn"));
transformed.put("dateOfInjury", claim.get("date_of_injury"));
transformed.put("occupation", claim.get("occupation"));
transformed.put("jurisdiction", claim.get("jurisdiction"));
transformed.put("claimType", claim.get("claim_type"));
transformed.put("status", claim.get("status"));
transformed.put("accidentDescription", claim.get("accident_description"));
Map<String, Object> flags = new HashMap<>();
flags.put("surgery", claim.get("surgery"));
flags.put("litigated", claim.get("litigated"));
flags.put("settled", claim.get("settlement"));
flags.put("controverted", claim.get("controvert"));
flags.put("vocRehab", claim.get("voc_rehab"));
flags.put("subrogated", claim.get("subrogated"));
flags.put("fraudulent", claim.get("fraudulent"));
flags.put("sdtf", claim.get("sdtf"));
flags.put("longshore", claim.get("longshore"));
transformed.put("flags", flags);
Map<String, Object> personnel = new HashMap<>();
personnel.put("adjuster", claim.get("adjuster"));
personnel.put("caseManager", claim.get("case_manager"));
transformed.put("personnel", personnel);
Map<String, Object> claimFinancials = (Map<String, Object>) claim.get("financials");
Map<String, Object> financials = new HashMap<>();
financials.put("total", transformFinancialCategory((Map<String, Object>) claimFinancials.get("total")));
financials.put("medical", transformFinancialCategory((Map<String, Object>) claimFinancials.get("medical")));
financials.put("indemnity", transformFinancialCategory((Map<String, Object>) claimFinancials.get("indemnity")));
financials.put("expense", transformFinancialCategory((Map<String, Object>) claimFinancials.get("expense")));
transformed.put("financials", financials);
return transformed;
}
private static Map<String, Object> transformFinancialCategory(Map<String, Object> category) {
Map<String, Object> transformed = new HashMap<>();
transformed.put("payments", category.get("payments"));
transformed.put("recovery", category.get("recovery"));
transformed.put("reserves", category.get("reserves"));
transformed.put("netIncurred", category.get("net_incurred"));
transformed.put("paidThisMonth", category.get("paid_this_month"));
transformed.put("incurredThisMonth", category.get("incurred_this_month"));
return transformed;
}
private static Map<String, Object> buildLossRunSchema() {
Map<String, Object> schema = new HashMap<>();
schema.put("type", "object");
Map<String, Object> properties = new HashMap<>();
// employer
Map<String, Object> employer = new HashMap<>();
employer.put("type", new Object[]{"string", "null"});
employer.put("description", "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy.");
properties.put("employer", employer);
// program
Map<String, Object> program = new HashMap<>();
program.put("type", new Object[]{"string", "null"});
program.put("description", "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions.");
properties.put("program", program);
// date_printed
Map<String, Object> datePrinted = new HashMap<>();
datePrinted.put("type", new Object[]{"string", "null"});
datePrinted.put("extend:type", "date");
datePrinted.put("description", "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.");
properties.put("date_printed", datePrinted);
// valued_as_of
Map<String, Object> valuedAsOf = new HashMap<>();
valuedAsOf.put("type", new Object[]{"string", "null"});
valuedAsOf.put("extend:type", "date");
valuedAsOf.put("description", "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.");
properties.put("valued_as_of", valuedAsOf);
// claims array
Map<String, Object> claimsArray = new HashMap<>();
claimsArray.put("type", "array");
claimsArray.put("items", buildClaimItemSchema());
claimsArray.put("description", "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats.");
properties.put("claims", claimsArray);
schema.put("properties", properties);
schema.put("required", new String[]{"claims", "program", "employer", "date_printed", "valued_as_of"});
schema.put("additionalProperties", false);
return schema;
}
private static Map<String, Object> buildClaimItemSchema() {
Map<String, Object> claimSchema = new HashMap<>();
claimSchema.put("type", "object");
Map<String, Object> properties = new HashMap<>();
// Identifiers
properties.put("claim_number", stringProperty("The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value."));
properties.put("employee_name", stringProperty("The name of the employee or claimant associated with this claim. May be labeled as 'Employee'."));
properties.put("employee_ssn", stringProperty("The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy."));
// Dates
properties.put("date_of_injury", dateProperty("The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar."));
properties.put("emp_report_date", dateProperty("The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar."));
properties.put("carrier_notify_date", dateProperty("The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'."));
properties.put("carrier_entry_date", dateProperty("The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'."));
properties.put("date_hired", dateProperty("The date the employee was hired by the employer. May be labeled as 'Date Hired'."));
// Claim details
properties.put("occupation", stringProperty("The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'."));
properties.put("jurisdiction", stringProperty("The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'."));
properties.put("claim_type", stringProperty("The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'."));
properties.put("status", stringProperty("The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'."));
properties.put("accident_description", stringProperty("A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where."));
// Status flags
properties.put("surgery", stringProperty("Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary."));
properties.put("litigated", stringProperty("Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary."));
properties.put("settlement", stringProperty("Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary."));
properties.put("controvert", stringProperty("Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary."));
properties.put("voc_rehab", stringProperty("Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary."));
properties.put("subrogated", stringProperty("Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary."));
properties.put("fraudulent", stringProperty("Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary."));
properties.put("sdtf", stringProperty("Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary."));
properties.put("longshore", stringProperty("Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary."));
// Personnel
properties.put("adjuster", stringProperty("The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'."));
properties.put("case_manager", stringProperty("The name or identifier of the case manager handling this claim, if applicable."));
// Financials
properties.put("financials", buildFinancialsSchema());
claimSchema.put("properties", properties);
claimSchema.put("required", new String[]{
"sdtf", "status", "surgery", "adjuster", "litigated", "longshore", "voc_rehab",
"claim_type", "controvert", "date_hired", "financials", "fraudulent", "occupation",
"settlement", "subrogated", "case_manager", "claim_number", "employee_ssn",
"jurisdiction", "employee_name", "date_of_injury", "emp_report_date",
"carrier_entry_date", "carrier_notify_date", "accident_description"
});
claimSchema.put("additionalProperties", false);
return claimSchema;
}
private static Map<String, Object> buildFinancialsSchema() {
Map<String, Object> financials = new HashMap<>();
financials.put("type", "object");
Map<String, Object> properties = new HashMap<>();
properties.put("total", buildFinancialCategorySchema("Total financials for this claim, summing indemnity, medical, and expense categories."));
properties.put("medical", buildFinancialCategorySchema("Financial details for the medical portion of the claim."));
properties.put("indemnity", buildFinancialCategorySchema("Financial details for indemnity (wage replacement) portion of the claim."));
properties.put("expense", buildFinancialCategorySchema("Financial details for the expense portion of the claim."));
financials.put("properties", properties);
financials.put("required", new String[]{"total", "expense", "medical", "indemnity"});
financials.put("additionalProperties", false);
financials.put("description", "Summary of financial amounts associated with this claim, broken down by category such as indemnity, medical, and expense. Amounts may be shown as reserves, payments, recoveries, net incurred, and monthly values.");
return financials;
}
private static Map<String, Object> buildFinancialCategorySchema(String description) {
Map<String, Object> category = new HashMap<>();
category.put("type", "object");
Map<String, Object> properties = new HashMap<>();
properties.put("payments", numberProperty("Total payments made to date"));
properties.put("recovery", numberProperty("Total amount recovered"));
properties.put("reserves", numberProperty("Total amount reserved"));
properties.put("net_incurred", numberProperty("Net incurred (reserves + payments - recoveries)"));
properties.put("paid_this_month", numberProperty("Amount paid this month"));
properties.put("incurred_this_month", numberProperty("Amount incurred this month"));
category.put("properties", properties);
category.put("required", new String[]{"payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"});
category.put("additionalProperties", false);
category.put("description", description);
return category;
}
private static Map<String, Object> stringProperty(String description) {
Map<String, Object> prop = new HashMap<>();
prop.put("type", new Object[]{"string", "null"});
prop.put("description", description);
return prop;
}
private static Map<String, Object> dateProperty(String description) {
Map<String, Object> prop = new HashMap<>();
prop.put("type", new Object[]{"string", "null"});
prop.put("extend:type", "date");
prop.put("description", description);
return prop;
}
private static Map<String, Object> numberProperty(String description) {
Map<String, Object> prop = new HashMap<>();
prop.put("type", new Object[]{"number", "null"});
prop.put("description", description);
return prop;
}
}package main
import (
"encoding/base64"
"encoding/json"
"flag"
"fmt"
"log"
"os"
"github.com/extend-ai/extend-go/client"
"github.com/extend-ai/extend-go/types"
)
// ClaimFinancials represents the financial details for a claim category.
type ClaimFinancials struct {
Payments *float64 `json:"payments"`
Recovery *float64 `json:"recovery"`
Reserves *float64 `json:"reserves"`
NetIncurred *float64 `json:"net_incurred"`
PaidThisMonth *float64 `json:"paid_this_month"`
IncurredThisMonth *float64 `json:"incurred_this_month"`
}
// ClaimFinancialsCategory groups financials by category.
type ClaimFinancialsCategory struct {
Total ClaimFinancials `json:"total"`
Medical ClaimFinancials `json:"medical"`
Indemnity ClaimFinancials `json:"indemnity"`
Expense ClaimFinancials `json:"expense"`
}
// Claim represents a single workers' compensation claim.
type Claim struct {
ClaimNumber *string `json:"claim_number"`
EmployeeName *string `json:"employee_name"`
EmployeeSSN *string `json:"employee_ssn"`
DateOfInjury *string `json:"date_of_injury"`
EmpReportDate *string `json:"emp_report_date"`
CarrierNotifyDate *string `json:"carrier_notify_date"`
CarrierEntryDate *string `json:"carrier_entry_date"`
DateHired *string `json:"date_hired"`
Occupation *string `json:"occupation"`
Jurisdiction *string `json:"jurisdiction"`
ClaimType *string `json:"claim_type"`
Status *string `json:"status"`
AccidentDescription *string `json:"accident_description"`
Surgery *string `json:"surgery"`
Litigated *string `json:"litigated"`
Settled *string `json:"settlement"`
Controvert *string `json:"controvert"`
VocRehab *string `json:"voc_rehab"`
Subrogated *string `json:"subrogated"`
Fraudulent *string `json:"fraudulent"`
SDTF *string `json:"sdtf"`
Longshore *string `json:"longshore"`
Adjuster *string `json:"adjuster"`
CaseManager *string `json:"case_manager"`
Financials ClaimFinancialsCategory `json:"financials"`
}
// LossRun represents the complete loss run document.
type LossRun struct {
Employer *string `json:"employer"`
Program *string `json:"program"`
DatePrinted *string `json:"date_printed"`
ValuedAsOf *string `json:"valued_as_of"`
Claims []Claim `json:"claims"`
}
// ExtractionResult is the output structure returned by the processing function.
type ExtractionResult struct {
Status string `json:"status"`
Document DocumentInfo `json:"document"`
Claims []ProcessedClaim `json:"claims"`
RawMarkdown string `json:"rawMarkdown"`
}
// DocumentInfo contains document-level metadata.
type DocumentInfo struct {
Employer *string `json:"employer"`
Program *string `json:"program"`
DateReported *string `json:"dateReported"`
ValuedAsOf *string `json:"valuedAsOf"`
}
// ProcessedClaim is the normalized output structure for each claim.
type ProcessedClaim struct {
ClaimNumber *string `json:"claimNumber"`
EmployeeName *string `json:"employeeName"`
EmployeeSSN *string `json:"employeeSSN"`
DateOfInjury *string `json:"dateOfInjury"`
Occupation *string `json:"occupation"`
Jurisdiction *string `json:"jurisdiction"`
ClaimType *string `json:"claimType"`
Status *string `json:"status"`
AccidentDescription *string `json:"accidentDescription"`
Flags ClaimFlags `json:"flags"`
Personnel PersonnelInfo `json:"personnel"`
Financials ProcessedFinancials `json:"financials"`
}
// ClaimFlags groups boolean/status flags.
type ClaimFlags struct {
Surgery *string `json:"surgery"`
Litigated *string `json:"litigated"`
Settled *string `json:"settled"`
Controverted *string `json:"controverted"`
VocRehab *string `json:"vocRehab"`
Subrogated *string `json:"subrogated"`
Fraudulent *string `json:"fraudulent"`
SDTF *string `json:"sdtf"`
Longshore *string `json:"longshore"`
}
// PersonnelInfo groups assigned personnel.
type PersonnelInfo struct {
Adjuster *string `json:"adjuster"`
CaseManager *string `json:"caseManager"`
}
// ProcessedFinancials groups financial data by category.
type ProcessedFinancials struct {
Total FinancialCategory `json:"total"`
Medical FinancialCategory `json:"medical"`
Indemnity FinancialCategory `json:"indemnity"`
Expense FinancialCategory `json:"expense"`
}
// FinancialCategory represents a single financial category.
type FinancialCategory struct {
Payments *float64 `json:"payments"`
Recovery *float64 `json:"recovery"`
Reserves *float64 `json:"reserves"`
NetIncurred *float64 `json:"netIncurred"`
PaidThisMonth *float64 `json:"paidThisMonth"`
IncurredThisMonth *float64 `json:"incurredThisMonth"`
}
// ProcessWorkersCompensationClaimSummary processes a workers' compensation loss run document.
// It uploads the file, parses it with agentic OCR, then extracts structured claim data.
func ProcessWorkersCompensationClaimSummary(filePath string) (*ExtractionResult, error) {
c := client.NewExtendClient(client.WithToken(os.Getenv("EXTEND_API_KEY")))
log.Printf("[WC Loss Run] Processing: %s", filePath)
// Convert local file to data URL (base64)
fileBuffer, err := os.ReadFile(filePath)
if err != nil {
return nil, fmt.Errorf("failed to read file: %w", err)
}
base64Str := base64.StdEncoding.EncodeToString(fileBuffer)
dataURL := fmt.Sprintf("data:application/pdf;base64,%s", base64Str)
// Step 1: Parse the loss run with agentic OCR
log.Println("[Step 1/2] Parsing loss run with agentic OCR...")
parseRun, err := c.ParseRuns.CreateAndPoll(&types.ParseRunConfig{
File: &types.FileInput{URL: dataURL},
Config: &types.ParseConfig{
Mode: "agentic_ocr",
OutputType: "markdown",
},
})
if err != nil {
return nil, fmt.Errorf("parse failed: %w", err)
}
if parseRun.Status != "PROCESSED" {
return nil, fmt.Errorf("parse failed with status: %s", parseRun.Status)
}
var parsedMarkdown string
for _, chunk := range parseRun.Output.Chunks {
parsedMarkdown += chunk.Content + "\n\n"
}
log.Printf("[Step 1/2] Parsed %d chunks. Markdown length: %d characters.",
len(parseRun.Output.Chunks), len(parsedMarkdown))
// Step 2: Extract structured claim data
log.Println("[Step 2/2] Extracting structured claim data...")
lossRunSchema := map[string]interface{}{
"type": "object",
"properties": map[string]interface{}{
"employer": map[string]interface{}{"type": []interface{}{"string", "null"}},
"program": map[string]interface{}{"type": []interface{}{"string", "null"}},
"date_printed": map[string]interface{}{"type": []interface{}{"string", "null"}, "extend:type": "date"},
"valued_as_of": map[string]interface{}{"type": []interface{}{"string", "null"}, "extend:type": "date"},
"claims": map[string]interface{}{"type": "array"},
},
}
extractRun, err := c.ExtractRuns.CreateAndPoll(&types.ExtractRunConfig{
File: &types.FileInput{URL: dataURL},
Config: &types.ExtractConfig{
Schema: lossRunSchema,
BaseProcessor: "extraction_performance",
},
})
if err != nil {
return nil, fmt.Errorf("extraction failed: %w", err)
}
if extractRun.Status != "PROCESSED" {
return nil, fmt.Errorf("extraction failed with status: %s", extractRun.Status)
}
// Parse the output into LossRun struct
outputBytes, _ := json.Marshal(extractRun.Output.Value)
var lossRunData LossRun
if err := json.Unmarshal(outputBytes, &lossRunData); err != nil {
return nil, fmt.Errorf("failed to parse extracted data: %w", err)
}
log.Println("[Step 2/2] Extraction complete.")
if lossRunData.Employer != nil {
log.Printf("Employer: %s", *lossRunData.Employer)
}
if lossRunData.Program != nil {
log.Printf("Program: %s", *lossRunData.Program)
}
if lossRunData.DatePrinted != nil {
log.Printf("Report Date: %s", *lossRunData.DatePrinted)
}
if lossRunData.ValuedAsOf != nil {
log.Printf("Valued As Of: %s", *lossRunData.ValuedAsOf)
}
log.Printf("Total Claims: %d", len(lossRunData.Claims))
// Example: Print first claim summary (if any)
if len(lossRunData.Claims) > 0 {
firstClaim := lossRunData.Claims[0]
log.Println("\n[Sample Claim #1]")
if firstClaim.ClaimNumber != nil {
log.Printf(" Claim #: %s", *firstClaim.ClaimNumber)
}
if firstClaim.EmployeeName != nil {
log.Printf(" Employee: %s", *firstClaim.EmployeeName)
}
if firstClaim.DateOfInjury != nil {
log.Printf(" DOI: %s", *firstClaim.DateOfInjury)
}
if firstClaim.Status != nil {
log.Printf(" Status: %s", *firstClaim.Status)
}
if firstClaim.Financials.Total.NetIncurred != nil {
log.Printf(" Total Net Incurred: $%.2f", *firstClaim.Financials.Total.NetIncurred)
}
}
// Build result structure
result := &ExtractionResult{
Status: "success",
Document: DocumentInfo{
Employer: lossRunData.Employer,
Program: lossRunData.Program,
DateReported: lossRunData.DatePrinted,
ValuedAsOf: lossRunData.ValuedAsOf,
},
Claims: make([]ProcessedClaim, len(lossRunData.Claims)),
RawMarkdown: parsedMarkdown,
}
for i, claim := range lossRunData.Claims {
result.Claims[i] = ProcessedClaim{
ClaimNumber: claim.ClaimNumber,
EmployeeName: claim.EmployeeName,
EmployeeSSN: claim.EmployeeSSN,
DateOfInjury: claim.DateOfInjury,
Occupation: claim.Occupation,
Jurisdiction: claim.Jurisdiction,
ClaimType: claim.ClaimType,
Status: claim.Status,
AccidentDescription: claim.AccidentDescription,
Flags: ClaimFlags{
Surgery: claim.Surgery,
Litigated: claim.Litigated,
Settled: claim.Settled,
Controverted: claim.Controvert,
VocRehab: claim.VocRehab,
Subrogated: claim.Subrogated,
Fraudulent: claim.Fraudulent,
SDTF: claim.SDTF,
Longshore: claim.Longshore,
},
Personnel: PersonnelInfo{
Adjuster: claim.Adjuster,
CaseManager: claim.CaseManager,
},
Financials: ProcessedFinancials{
Total: FinancialCategory{
Payments: claim.Financials.Total.Payments,
Recovery: claim.Financials.Total.Recovery,
Reserves: claim.Financials.Total.Reserves,
NetIncurred: claim.Financials.Total.NetIncurred,
PaidThisMonth: claim.Financials.Total.PaidThisMonth,
IncurredThisMonth: claim.Financials.Total.IncurredThisMonth,
},
Medical: FinancialCategory{
Payments: claim.Financials.Medical.Payments,
Recovery: claim.Financials.Medical.Recovery,
Reserves: claim.Financials.Medical.Reserves,
NetIncurred: claim.Financials.Medical.NetIncurred,
PaidThisMonth: claim.Financials.Medical.PaidThisMonth,
IncurredThisMonth: claim.Financials.Medical.IncurredThisMonth,
},
Indemnity: FinancialCategory{
Payments: claim.Financials.Indemnity.Payments,
Recovery: claim.Financials.Indemnity.Recovery,
Reserves: claim.Financials.Indemnity.Reserves,
NetIncurred: claim.Financials.Indemnity.NetIncurred,
PaidThisMonth: claim.Financials.Indemnity.PaidThisMonth,
IncurredThisMonth: claim.Financials.Indemnity.IncurredThisMonth,
},
Expense: FinancialCategory{
Payments: claim.Financials.Expense.Payments,
Recovery: claim.Financials.Expense.Recovery,
Reserves: claim.Financials.Expense.Reserves,
NetIncurred: claim.Financials.Expense.NetIncurred,
PaidThisMonth: claim.Financials.Expense.PaidThisMonth,
IncurredThisMonth: claim.Financials.Expense.IncurredThisMonth,
},
},
}
}
return result, nil
}
func main() {
flag.Parse()
filePath := flag.Arg(0)
if filePath == "" {
filePath = "__FILE_PATH__"
}
result, err := ProcessWorkersCompensationClaimSummary(filePath)
if err != nil {
log.Fatalf("Error: %v", err)
}
log.Println("\n=== EXTRACTION RESULT ===")
resultJSON, _ := json.MarshalIndent(result, "", " ")
fmt.Println(string(resultJSON))
}// Deploy the "Workers' Compensation Claim Summary" 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/loss-run-report.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: loss-run-report).
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, "loss-run-report.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": "Workers' Compensation Claim Summary Processing Pipeline",
"steps": [
{
"name": "startTrigger1",
"type": "TRIGGER",
"next": [
{
"step": "parse1"
}
]
},
{
"name": "parse1",
"type": "PARSE",
"config": {
"parseConfig": {
"blockOptions": {
"text": {
"agentic": {
"enabled": true
}
}
},
"chunkingStrategy": {
"type": "document"
}
}
},
"next": [
{
"step": "extraction2"
}
]
},
{
"name": "extraction2",
"type": "EXTRACT",
"config": {
"extractorConfig": {
"schema": {
"type": "object",
"required": [
"claims",
"program",
"employer",
"date_printed",
"valued_as_of"
],
"properties": {
"claims": {
"type": "array",
"items": {
"type": "object",
"required": [
"sdtf",
"status",
"surgery",
"adjuster",
"litigated",
"longshore",
"voc_rehab",
"claim_type",
"controvert",
"date_hired",
"financials",
"fraudulent",
"occupation",
"settlement",
"subrogated",
"case_manager",
"claim_number",
"employee_ssn",
"jurisdiction",
"employee_name",
"date_of_injury",
"emp_report_date",
"carrier_entry_date",
"carrier_notify_date",
"accident_description"
],
"properties": {
"sdtf": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary."
},
"status": {
"type": [
"string",
"null"
],
"description": "The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'."
},
"surgery": {
"type": [
"string",
"null"
],
"description": "Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary."
},
"adjuster": {
"type": [
"string",
"null"
],
"description": "The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'."
},
"litigated": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary."
},
"longshore": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary."
},
"voc_rehab": {
"type": [
"string",
"null"
],
"description": "Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary."
},
"claim_type": {
"type": [
"string",
"null"
],
"description": "The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'."
},
"controvert": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary."
},
"date_hired": {
"type": [
"string",
"null"
],
"description": "The date the employee was hired by the employer. May be labeled as 'Date Hired'.",
"extend:type": "date"
},
"financials": {
"type": "object",
"required": [
"total",
"expense",
"medical",
"indemnity"
],
"properties": {
"total": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month"
],
"properties": {
"payments": {
"type": [
"number",
"null"
],
"description": "The total payments made to date on this claim."
},
"recovery": {
"type": [
"number",
"null"
],
"description": "The total amount recovered on this claim."
},
"reserves": {
"type": [
"number",
"null"
],
"description": "The total amount reserved for this claim."
},
"net_incurred": {
"type": [
"number",
"null"
],
"description": "The total net incurred amount for this claim (reserves plus payments minus recoveries)."
},
"paid_this_month": {
"type": [
"number",
"null"
],
"description": "The total amount paid during the current month."
},
"incurred_this_month": {
"type": [
"number",
"null"
],
"description": "The total amount incurred during the current month."
}
},
"description": "Total financials for this claim, summing indemnity, medical, and expense categories.",
"additionalProperties": false
},
"expense": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month"
],
"properties": {
"payments": {
"type": [
"number",
"null"
],
"description": "The total expense payments made to date on this claim."
},
"recovery": {
"type": [
"number",
"null"
],
"description": "The amount recovered for expenses on this claim."
},
"reserves": {
"type": [
"number",
"null"
],
"description": "The amount reserved for expenses on this claim."
},
"net_incurred": {
"type": [
"number",
"null"
],
"description": "The net incurred expense amount (reserves plus payments minus recoveries)."
},
"paid_this_month": {
"type": [
"number",
"null"
],
"description": "The expense amount paid during the current month."
},
"incurred_this_month": {
"type": [
"number",
"null"
],
"description": "The expense amount incurred during the current month."
}
},
"description": "Financial details for the expense portion of the claim.",
"additionalProperties": false
},
"medical": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month"
],
"properties": {
"payments": {
"type": [
"number",
"null"
],
"description": "The total medical payments made to date on this claim."
},
"recovery": {
"type": [
"number",
"null"
],
"description": "The amount recovered for medical on this claim."
},
"reserves": {
"type": [
"number",
"null"
],
"description": "The amount reserved for medical payments on this claim."
},
"net_incurred": {
"type": [
"number",
"null"
],
"description": "The net incurred medical amount (reserves plus payments minus recoveries)."
},
"paid_this_month": {
"type": [
"number",
"null"
],
"description": "The medical amount paid during the current month."
},
"incurred_this_month": {
"type": [
"number",
"null"
],
"description": "The medical amount incurred during the current month."
}
},
"description": "Financial details for the medical portion of the claim.",
"additionalProperties": false
},
"indemnity": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month"
],
"properties": {
"payments": {
"type": [
"number",
"null"
],
"description": "The total indemnity payments made to date on this claim."
},
"recovery": {
"type": [
"number",
"null"
],
"description": "The amount recovered for indemnity on this claim."
},
"reserves": {
"type": [
"number",
"null"
],
"description": "The amount reserved for indemnity payments on this claim."
},
"net_incurred": {
"type": [
"number",
"null"
],
"description": "The net incurred indemnity amount (reserves plus payments minus recoveries)."
},
"paid_this_month": {
"type": [
"number",
"null"
],
"description": "The indemnity amount paid during the current month."
},
"incurred_this_month": {
"type": [
"number",
"null"
],
"description": "The indemnity amount incurred during the current month."
}
},
"description": "Financial details for indemnity (wage replacement) portion of the claim.",
"additionalProperties": false
}
},
"description": "Summary of financial amounts associated with this claim, broken down by category such as indemnity, medical, and expense. Amounts may be shown as reserves, payments, recoveries, net incurred, and monthly values.",
"additionalProperties": false
},
"fraudulent": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary."
},
"occupation": {
"type": [
"string",
"null"
],
"description": "The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'."
},
"settlement": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary."
},
"subrogated": {
"type": [
"string",
"null"
],
"description": "Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary."
},
"case_manager": {
"type": [
"string",
"null"
],
"description": "The name or identifier of the case manager handling this claim, if applicable."
},
"claim_number": {
"type": [
"string",
"null"
],
"description": "The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value."
},
"employee_ssn": {
"type": [
"string",
"null"
],
"description": "The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy."
},
"jurisdiction": {
"type": [
"string",
"null"
],
"description": "The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'."
},
"employee_name": {
"type": [
"string",
"null"
],
"description": "The name of the employee or claimant associated with this claim. May be labeled as 'Employee'."
},
"date_of_injury": {
"type": [
"string",
"null"
],
"description": "The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar.",
"extend:type": "date"
},
"emp_report_date": {
"type": [
"string",
"null"
],
"description": "The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar.",
"extend:type": "date"
},
"carrier_entry_date": {
"type": [
"string",
"null"
],
"description": "The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'.",
"extend:type": "date"
},
"carrier_notify_date": {
"type": [
"string",
"null"
],
"description": "The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'.",
"extend:type": "date"
},
"accident_description": {
"type": [
"string",
"null"
],
"description": "A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where."
}
},
"additionalProperties": false
},
"description": "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats."
},
"program": {
"type": [
"string",
"null"
],
"description": "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions."
},
"employer": {
"type": [
"string",
"null"
],
"description": "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy."
},
"date_printed": {
"type": [
"string",
"null"
],
"description": "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.",
"extend:type": "date"
},
"valued_as_of": {
"type": [
"string",
"null"
],
"description": "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.",
"extend:type": "date"
}
},
"additionalProperties": false
},
"baseProcessor": "extraction_performance",
"advancedOptions": {
"reviewAgent": {
"enabled": true
},
"advancedMultimodalEnabled": true
}
}
}
}
]
};
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); });
#!/usr/bin/env python3
"""
Deploy the "Workers' Compensation Claim Summary" 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/loss-run-report.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)
python provision.py
Generated by doc1 (template: loss-run-report).
"""
import json
import os
import sys
from pathlib import Path
from typing import Any, Dict, Optional
import httpx
API = "https://api.extend.ai"
VERSION = "2026-02-09"
API_KEY = os.getenv("EXTEND_API_KEY")
if not API_KEY:
print("Set EXTEND_API_KEY first.", file=sys.stderr)
sys.exit(1)
STATE_DIR = Path.cwd() / ".extend"
STATE_FILE = STATE_DIR / "loss-run-report.json"
def load_state() -> Dict[str, Any]:
if STATE_FILE.exists():
return json.loads(STATE_FILE.read_text())
return {}
def save_state(state: Dict[str, Any]) -> None:
STATE_DIR.mkdir(parents=True, exist_ok=True)
STATE_FILE.write_text(json.dumps(state, indent=2))
async def api(
method: str, path_name: str, body: Optional[Dict[str, Any]] = None
) -> Any:
headers = {
"Authorization": f"Bearer {API_KEY}",
"x-extend-api-version": VERSION,
}
if body:
headers["Content-Type"] = "application/json"
async with httpx.AsyncClient() as client:
res = await client.request(
method,
API + path_name,
headers=headers,
json=body,
)
try:
data = res.json()
except Exception:
data = {}
if not res.is_success:
error_msg = json.dumps(data)[:300]
raise RuntimeError(
f"{method} {path_name} failed ({res.status_code}): {error_msg}"
)
return data
WORKFLOW = {
"name": "Workers' Compensation Claim Summary Processing Pipeline",
"steps": [
{
"name": "startTrigger1",
"type": "TRIGGER",
"next": [{"step": "parse1"}],
},
{
"name": "parse1",
"type": "PARSE",
"config": {
"parseConfig": {
"blockOptions": {
"text": {
"agentic": {
"enabled": True,
},
},
},
"chunkingStrategy": {
"type": "document",
},
}
},
"next": [{"step": "extraction2"}],
},
{
"name": "extraction2",
"type": "EXTRACT",
"config": {
"extractorConfig": {
"schema": {
"type": "object",
"required": [
"claims",
"program",
"employer",
"date_printed",
"valued_as_of",
],
"properties": {
"claims": {
"type": "array",
"items": {
"type": "object",
"required": [
"sdtf",
"status",
"surgery",
"adjuster",
"litigated",
"longshore",
"voc_rehab",
"claim_type",
"controvert",
"date_hired",
"financials",
"fraudulent",
"occupation",
"settlement",
"subrogated",
"case_manager",
"claim_number",
"employee_ssn",
"jurisdiction",
"employee_name",
"date_of_injury",
"emp_report_date",
"carrier_entry_date",
"carrier_notify_date",
"accident_description",
],
"properties": {
"sdtf": {
"type": ["string", "null"],
"description": "Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary.",
},
"status": {
"type": ["string", "null"],
"description": "The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'.",
},
"surgery": {
"type": ["string", "null"],
"description": "Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary.",
},
"adjuster": {
"type": ["string", "null"],
"description": "The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'.",
},
"litigated": {
"type": ["string", "null"],
"description": "Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary.",
},
"longshore": {
"type": ["string", "null"],
"description": "Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary.",
},
"voc_rehab": {
"type": ["string", "null"],
"description": "Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary.",
},
"claim_type": {
"type": ["string", "null"],
"description": "The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'.",
},
"controvert": {
"type": ["string", "null"],
"description": "Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary.",
},
"date_hired": {
"type": ["string", "null"],
"description": "The date the employee was hired by the employer. May be labeled as 'Date Hired'.",
"extend:type": "date",
},
"financials": {
"type": "object",
"required": ["total", "expense", "medical", "indemnity"],
"properties": {
"total": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month",
],
"properties": {
"payments": {
"type": ["number", "null"],
"description": "The total payments made to date on this claim.",
},
"recovery": {
"type": ["number", "null"],
"description": "The total amount recovered on this claim.",
},
"reserves": {
"type": ["number", "null"],
"description": "The total amount reserved for this claim.",
},
"net_incurred": {
"type": ["number", "null"],
"description": "The total net incurred amount for this claim (reserves plus payments minus recoveries).",
},
"paid_this_month": {
"type": ["number", "null"],
"description": "The total amount paid during the current month.",
},
"incurred_this_month": {
"type": ["number", "null"],
"description": "The total amount incurred during the current month.",
},
},
"description": "Total financials for this claim, summing indemnity, medical, and expense categories.",
"additionalProperties": False,
},
"expense": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month",
],
"properties": {
"payments": {
"type": ["number", "null"],
"description": "The total expense payments made to date on this claim.",
},
"recovery": {
"type": ["number", "null"],
"description": "The amount recovered for expenses on this claim.",
},
"reserves": {
"type": ["number", "null"],
"description": "The amount reserved for expenses on this claim.",
},
"net_incurred": {
"type": ["number", "null"],
"description": "The net incurred expense amount (reserves plus payments minus recoveries).",
},
"paid_this_month": {
"type": ["number", "null"],
"description": "The expense amount paid during the current month.",
},
"incurred_this_month": {
"type": ["number", "null"],
"description": "The expense amount incurred during the current month.",
},
},
"description": "Financial details for the expense portion of the claim.",
"additionalProperties": False,
},
"medical": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month",
],
"properties": {
"payments": {
"type": ["number", "null"],
"description": "The total medical payments made to date on this claim.",
},
"recovery": {
"type": ["number", "null"],
"description": "The amount recovered for medical on this claim.",
},
"reserves": {
"type": ["number", "null"],
"description": "The amount reserved for medical payments on this claim.",
},
"net_incurred": {
"type": ["number", "null"],
"description": "The net incurred medical amount (reserves plus payments minus recoveries).",
},
"paid_this_month": {
"type": ["number", "null"],
"description": "The medical amount paid during the current month.",
},
"incurred_this_month": {
"type": ["number", "null"],
"description": "The medical amount incurred during the current month.",
},
},
"description": "Financial details for the medical portion of the claim.",
"additionalProperties": False,
},
"indemnity": {
"type": "object",
"required": [
"payments",
"recovery",
"reserves",
"net_incurred",
"paid_this_month",
"incurred_this_month",
],
"properties": {
"payments": {
"type": ["number", "null"],
"description": "The total indemnity payments made to date on this claim.",
},
"recovery": {
"type": ["number", "null"],
"description": "The amount recovered for indemnity on this claim.",
},
"reserves": {
"type": ["number", "null"],
"description": "The amount reserved for indemnity payments on this claim.",
},
"net_incurred": {
"type": ["number", "null"],
"description": "The net incurred indemnity amount (reserves plus payments minus recoveries).",
},
"paid_this_month": {
"type": ["number", "null"],
"description": "The indemnity amount paid during the current month.",
},
"incurred_this_month": {
"type": ["number", "null"],
"description": "The indemnity amount incurred during the current month.",
},
},
"description": "Financial details for indemnity (wage replacement) portion of the claim.",
"additionalProperties": False,
},
},
"description": "Summary of financial amounts associated with this claim, broken down by category such as indemnity, medical, and expense. Amounts may be shown as reserves, payments, recoveries, net incurred, and monthly values.",
"additionalProperties": False,
},
"fraudulent": {
"type": ["string", "null"],
"description": "Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary.",
},
"occupation": {
"type": ["string", "null"],
"description": "The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'.",
},
"settlement": {
"type": ["string", "null"],
"description": "Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary.",
},
"subrogated": {
"type": ["string", "null"],
"description": "Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary.",
},
"case_manager": {
"type": ["string", "null"],
"description": "The name or identifier of the case manager handling this claim, if applicable.",
},
"claim_number": {
"type": ["string", "null"],
"description": "The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value.",
},
"employee_ssn": {
"type": ["string", "null"],
"description": "The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy.",
},
"jurisdiction": {
"type": ["string", "null"],
"description": "The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'.",
},
"employee_name": {
"type": ["string", "null"],
"description": "The name of the employee or claimant associated with this claim. May be labeled as 'Employee'.",
},
"date_of_injury": {
"type": ["string", "null"],
"description": "The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar.",
"extend:type": "date",
},
"emp_report_date": {
"type": ["string", "null"],
"description": "The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar.",
"extend:type": "date",
},
"carrier_entry_date": {
"type": ["string", "null"],
"description": "The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'.",
"extend:type": "date",
},
"carrier_notify_date": {
"type": ["string", "null"],
"description": "The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'.",
"extend:type": "date",
},
"accident_description": {
"type": ["string", "null"],
"description": "A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where.",
},
},
"additionalProperties": False,
},
"description": "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats.",
},
"program": {
"type": ["string", "null"],
"description": "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions.",
},
"employer": {
"type": ["string", "null"],
"description": "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy.",
},
"date_printed": {
"type": ["string", "null"],
"description": "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.",
"extend:type": "date",
},
"valued_as_of": {
"type": ["string", "null"],
"description": "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.",
"extend:type": "date",
},
},
"additionalProperties": False,
},
"baseProcessor": "extraction_performance",
"advancedOptions": {
"reviewAgent": {
"enabled": True,
},
"advancedMultimodalEnabled": True,
},
}
},
},
],
}
async def main() -> None:
state = load_state()
print(f'Deploying "{WORKFLOW["name"]}…"')
if state.get("workflowId"):
wf_id = state["workflowId"]
print(f"✓ workflow already provisioned ({wf_id}) — updating steps")
await api("POST", f"/workflows/{wf_id}", {"steps": WORKFLOW["steps"]})
else:
try:
list_resp = await api(
"GET",
f"/workflows?name={httpx.URL(WORKFLOW['name']).params}",
)
items = list_resp.get("data") or list_resp.get("items") or []
existing = next(
(item for item in items if item.get("name") == WORKFLOW["name"]),
None,
)
if existing and existing.get("id"):
state["workflowId"] = existing["id"]
save_state(state)
print(
f'✓ workflow "{WORKFLOW["name"]}" found in your account ({existing["id"]}) — updating steps'
)
await api(
"POST",
f"/workflows/{existing['id']}",
{"steps": WORKFLOW["steps"]},
)
except Exception:
pass
if not state.get("workflowId"):
created = await api("POST", "/workflows", WORKFLOW)
wf_id = created.get("id") or created.get("workflow", {}).get("id")
if not wf_id:
raise RuntimeError(
"Could not read created workflow id from response"
)
state["workflowId"] = wf_id
save_state(state)
print(f"+ created workflow ({wf_id})")
wf_id = state["workflowId"]
try:
await api("POST", f"/workflows/{wf_id}/versions", {})
except Exception:
pass
print("\nDone. Run documents through it with:")
print(
f' POST {API}/workflow_runs {{ workflow: {{ id: "{wf_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), file=sys.stderr)
sys.exit(1)import com.fasterxml.jackson.databind.ObjectMapper;
import java.io.File;
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.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class WorkersCompensationProvisioner {
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("loss-run-report.json");
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final HttpClient HTTP_CLIENT = HttpClient.newHttpClient();
static {
if (API_KEY == null || API_KEY.isEmpty()) {
System.err.println("Set EXTEND_API_KEY first.");
System.exit(1);
}
}
static class State {
public String workflowId;
public State() {}
public State(String workflowId) { this.workflowId = workflowId; }
}
private static State loadState() throws IOException {
if (Files.exists(STATE_FILE)) {
return MAPPER.readValue(STATE_FILE.toFile(), State.class);
}
return new State();
}
private static void saveState(State state) throws IOException {
Files.createDirectories(STATE_DIR);
MAPPER.writerWithDefaultPrettyPrinter().writeValue(STATE_FILE.toFile(), state);
}
private static Map<String, Object> api(String method, String pathName, Object body) throws Exception {
HttpRequest.Builder requestBuilder = HttpRequest.newBuilder()
.uri(URI.create(API + pathName))
.header("Authorization", "Bearer " + API_KEY)
.header("x-extend-api-version", VERSION);
if (body != null) {
String jsonBody = MAPPER.writeValueAsString(body);
requestBuilder.header("Content-Type", "application/json");
requestBuilder.method(method, HttpRequest.BodyPublishers.ofString(jsonBody));
} else {
requestBuilder.method(method, HttpRequest.BodyPublishers.noBody());
}
HttpRequest request = requestBuilder.build();
HttpResponse<String> response = HTTP_CLIENT.send(request, HttpResponse.BodyHandlers.ofString());
Map<String, Object> data = new LinkedHashMap<>();
if (!response.body().isEmpty()) {
try {
data = MAPPER.readValue(response.body(), Map.class);
} catch (Exception ignored) {}
}
if (response.statusCode() < 200 || response.statusCode() >= 300) {
String bodyPreview = MAPPER.writeValueAsString(data);
if (bodyPreview.length() > 300) {
bodyPreview = bodyPreview.substring(0, 300);
}
throw new Exception(String.format("%s %s failed (%d): %s", method, pathName, response.statusCode(), bodyPreview));
}
return data;
}
@SuppressWarnings("unchecked")
private static Map<String, Object> buildWorkflow() {
Map<String, Object> financialTemplate = new LinkedHashMap<>();
financialTemplate.put("type", "object");
financialTemplate.put("required", List.of("payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"));
Map<String, Object> props = new LinkedHashMap<>();
for (String key : List.of("payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month")) {
Map<String, Object> prop = new LinkedHashMap<>();
prop.put("type", List.of("number", "null"));
props.put(key, prop);
}
financialTemplate.put("properties", props);
financialTemplate.put("additionalProperties", false);
Map<String, Object> financialsProps = new LinkedHashMap<>();
for (String cat : List.of("total", "expense", "medical", "indemnity")) {
financialsProps.put(cat, MAPPER.convertValue(financialTemplate, Map.class));
}
Map<String, Object> financials = new LinkedHashMap<>();
financials.put("type", "object");
financials.put("required", List.of("total", "expense", "medical", "indemnity"));
financials.put("properties", financialsProps);
financials.put("additionalProperties", false);
Map<String, Object> claimProps = new LinkedHashMap<>();
claimProps.put("sdtf", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary."));
claimProps.put("status", Map.of("type", List.of("string", "null"), "description", "The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'."));
claimProps.put("surgery", Map.of("type", List.of("string", "null"), "description", "Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary."));
claimProps.put("adjuster", Map.of("type", List.of("string", "null"), "description", "The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'."));
claimProps.put("litigated", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary."));
claimProps.put("longshore", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary."));
claimProps.put("voc_rehab", Map.of("type", List.of("string", "null"), "description", "Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary."));
claimProps.put("claim_type", Map.of("type", List.of("string", "null"), "description", "The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'."));
claimProps.put("controvert", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary."));
claimProps.put("date_hired", Map.of("type", List.of("string", "null"), "description", "The date the employee was hired by the employer. May be labeled as 'Date Hired'.", "extend:type", "date"));
claimProps.put("financials", financials);
claimProps.put("fraudulent", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary."));
claimProps.put("occupation", Map.of("type", List.of("string", "null"), "description", "The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'."));
claimProps.put("settlement", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary."));
claimProps.put("subrogated", Map.of("type", List.of("string", "null"), "description", "Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary."));
claimProps.put("case_manager", Map.of("type", List.of("string", "null"), "description", "The name or identifier of the case manager handling this claim, if applicable."));
claimProps.put("claim_number", Map.of("type", List.of("string", "null"), "description", "The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value."));
claimProps.put("employee_ssn", Map.of("type", List.of("string", "null"), "description", "The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy."));
claimProps.put("jurisdiction", Map.of("type", List.of("string", "null"), "description", "The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'."));
claimProps.put("employee_name", Map.of("type", List.of("string", "null"), "description", "The name of the employee or claimant associated with this claim. May be labeled as 'Employee'."));
claimProps.put("date_of_injury", Map.of("type", List.of("string", "null"), "description", "The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar.", "extend:type", "date"));
claimProps.put("emp_report_date", Map.of("type", List.of("string", "null"), "description", "The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar.", "extend:type", "date"));
claimProps.put("carrier_entry_date", Map.of("type", List.of("string", "null"), "description", "The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'.", "extend:type", "date"));
claimProps.put("carrier_notify_date", Map.of("type", List.of("string", "null"), "description", "The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'.", "extend:type", "date"));
claimProps.put("accident_description", Map.of("type", List.of("string", "null"), "description", "A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where."));
Map<String, Object> claimItem = new LinkedHashMap<>();
claimItem.put("type", "object");
claimItem.put("required", List.of("sdtf", "status", "surgery", "adjuster", "litigated", "longshore", "voc_rehab", "claim_type", "controvert", "date_hired", "financials", "fraudulent", "occupation", "settlement", "subrogated", "case_manager", "claim_number", "employee_ssn", "jurisdiction", "employee_name", "date_of_injury", "emp_report_date", "carrier_entry_date", "carrier_notify_date", "accident_description"));
claimItem.put("properties", claimProps);
claimItem.put("additionalProperties", false);
Map<String, Object> claimsArray = new LinkedHashMap<>();
claimsArray.put("type", "array");
claimsArray.put("items", claimItem);
claimsArray.put("description", "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats.");
Map<String, Object> schemaProps = new LinkedHashMap<>();
schemaProps.put("claims", claimsArray);
schemaProps.put("program", Map.of("type", List.of("string", "null"), "description", "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions."));
schemaProps.put("employer", Map.of("type", List.of("string", "null"), "description", "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy."));
schemaProps.put("date_printed", Map.of("type", List.of("string", "null"), "description", "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.", "extend:type", "date"));
schemaProps.put("valued_as_of", Map.of("type", List.of("string", "null"), "description", "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.", "extend:type", "date"));
Map<String, Object> schema = new LinkedHashMap<>();
schema.put("type", "object");
schema.put("required", List.of("claims", "program", "employer", "date_printed", "valued_as_of"));
schema.put("properties", schemaProps);
schema.put("additionalProperties", false);
Map<String, Object> extractorConfig = new LinkedHashMap<>();
extractorConfig.put("schema", schema);
extractorConfig.put("baseProcessor", "extraction_performance");
Map<String, Object> reviewAgent = new LinkedHashMap<>();
reviewAgent.put("enabled", true);
Map<String, Object> advancedOptions = new LinkedHashMap<>();
advancedOptions.put("reviewAgent", reviewAgent);
advancedOptions.put("advancedMultimodalEnabled", true);
extractorConfig.put("advancedOptions", advancedOptions);
Map<String, Object> extraction2Config = new LinkedHashMap<>();
extraction2Config.put("extractorConfig", extractorConfig);
Map<String, Object> parseConfig = new LinkedHashMap<>();
Map<String, Object> blockOptions = new LinkedHashMap<>();
Map<String, Object> text = new LinkedHashMap<>();
Map<String, Object> agentic = new LinkedHashMap<>();
agentic.put("enabled", true);
text.put("agentic", agentic);
blockOptions.put("text", text);
parseConfig.put("blockOptions", blockOptions);
Map<String, Object> chunkingStrategy = new LinkedHashMap<>();
chunkingStrategy.put("type", "document");
parseConfig.put("chunkingStrategy", chunkingStrategy);
Map<String, Object> parse1Config = new LinkedHashMap<>();
parse1Config.put("parseConfig", parseConfig);
Map<String, Object> trigger = new LinkedHashMap<>();
trigger.put("step", "parse1");
Map<String, Object> startTrigger = new LinkedHashMap<>();
startTrigger.put("name", "startTrigger1");
startTrigger.put("type", "TRIGGER");
startTrigger.put("next", List.of(trigger));
Map<String, Object> parse1Next = new LinkedHashMap<>();
parse1Next.put("step", "extraction2");
Map<String, Object> parse1Step = new LinkedHashMap<>();
parse1Step.put("name", "parse1");
parse1Step.put("type", "PARSE");
parse1Step.put("config", parse1Config);
parse1Step.put("next", List.of(parse1Next));
Map<String, Object> extraction2Step = new LinkedHashMap<>();
extraction2Step.put("name", "extraction2");
extraction2Step.put("type", "EXTRACT");
extraction2Step.put("config", extraction2Config);
Map<String, Object> workflow = new LinkedHashMap<>();
workflow.put("name", "Workers' Compensation Claim Summary Processing Pipeline");
workflow.put("steps", List.of(startTrigger, parse1Step, extraction2Step));
return workflow;
}
@SuppressWarnings("unchecked")
public static void main(String[] args) {
try {
State state = loadState();
Map<String, Object> workflow = buildWorkflow();
String workflowName = (String) workflow.get("name");
System.out.println("Deploying \"" + workflowName + "\"…");
if (state.workflowId != null && !state.workflowId.isEmpty()) {
System.out.println("✓ workflow already provisioned (" + state.workflowId + ") — updating steps");
api("POST", "/workflows/" + state.workflowId, Map.of("steps", workflow.get("steps")));
} else {
try {
String encoded = URLEncoder.encode(workflowName, StandardCharsets.UTF_8);
Map<String, Object> list = api("GET", "/workflows?name=" + encoded, null);
List<Map<String, Object>> items = (List<Map<String, Object>>) (list.getOrDefault("data", list.getOrDefault("items", List.of())));
String existingId = null;
for (Map<String, Object> item : items) {
if (workflowName.equals(item.get("name"))) {
existingId = (String) item.get("id");
break;
}
}
if (existingId != null) {
state.workflowId = existingId;
saveState(state);
System.out.println("✓ workflow \"" + workflowName + "\" found in your account (" + existingId + ") — updating steps");
api("POST", "/workflows/" + existingId, Map.of("steps", workflow.get("steps")));
}
} catch (Exception ignored) {}
if (state.workflowId == null || state.workflowId.isEmpty()) {
Map<String, Object> created = api("POST", "/workflows", workflow);
String wfId = (String) created.getOrDefault("id", null);
if (wfId == null) {
Map<String, Object> workflowObj = (Map<String, Object>) created.get("workflow");
if (workflowObj != null) {
wfId = (String) workflowObj.get("id");
}
}
if (wfId == null) {
throw new Exception("Could not read created workflow id from response");
}
state.workflowId = wfId;
saveState(state);
System.out.println("+ created workflow (" + wfId + ")");
}
}
try {
api("POST", "/workflows/" + state.workflowId + "/versions", Map.of());
} catch (Exception ignored) {}
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);
System.exit(1);
}
}
}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 FinancialDetails struct {
Payments *float64 `json:"payments"`
Recovery *float64 `json:"recovery"`
Reserves *float64 `json:"reserves"`
NetIncurred *float64 `json:"net_incurred"`
PaidThisMonth *float64 `json:"paid_this_month"`
IncurredThisMonth *float64 `json:"incurred_this_month"`
}
type Financials struct {
Total FinancialDetails `json:"total"`
Expense FinancialDetails `json:"expense"`
Medical FinancialDetails `json:"medical"`
Indemnity FinancialDetails `json:"indemnity"`
}
type ClaimItem struct {
SDTF string `json:"sdtf"`
Status *string `json:"status"`
Surgery *string `json:"surgery"`
Adjuster *string `json:"adjuster"`
Litigated *string `json:"litigated"`
Longshore *string `json:"longshore"`
VocRehab *string `json:"voc_rehab"`
ClaimType *string `json:"claim_type"`
Controvert *string `json:"controvert"`
DateHired *string `json:"date_hired"`
Financials Financials `json:"financials"`
Fraudulent *string `json:"fraudulent"`
Occupation *string `json:"occupation"`
Settlement *string `json:"settlement"`
Subrogated *string `json:"subrogated"`
CaseManager *string `json:"case_manager"`
ClaimNumber *string `json:"claim_number"`
EmployeeSSN *string `json:"employee_ssn"`
Jurisdiction *string `json:"jurisdiction"`
EmployeeName *string `json:"employee_name"`
DateOfInjury *string `json:"date_of_injury"`
EmpReportDate *string `json:"emp_report_date"`
CarrierEntryDate *string `json:"carrier_entry_date"`
CarrierNotifyDate *string `json:"carrier_notify_date"`
AccidentDescription *string `json:"accident_description"`
}
type WorkflowStep struct {
Name string `json:"name"`
Type string `json:"type"`
Config map[string]interface{} `json:"config,omitempty"`
Next []map[string]string `json:"next,omitempty"`
}
type WorkflowRequest struct {
Name string `json:"name"`
Steps []WorkflowStep `json:"steps"`
}
type WorkflowResponse struct {
ID string `json:"id"`
Workflow struct {
ID string `json:"id"`
} `json:"workflow"`
}
type WorkflowListResponse struct {
Data []map[string]interface{} `json:"data"`
Items []map[string]interface{} `json:"items"`
}
var (
apiKey string
stateDir string
stateFile string
state State
)
func init() {
apiKey = os.Getenv("EXTEND_API_KEY")
if apiKey == "" {
fmt.Fprintln(os.Stderr, "Set EXTEND_API_KEY first.")
os.Exit(1)
}
wd, _ := os.Getwd()
stateDir = filepath.Join(wd, ".extend")
stateFile = filepath.Join(stateDir, "loss-run-report.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, _ := json.MarshalIndent(state, "", " ")
return os.WriteFile(stateFile, data, 0644)
}
func apiCall(method string, pathName string, body interface{}) (map[string]interface{}, error) {
var reqBody io.Reader
if body != nil {
jsonData, _ := json.Marshal(body)
reqBody = bytes.NewReader(jsonData)
}
req, _ := http.NewRequest(method, API+pathName, reqBody)
req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
req.Header.Set("x-extend-api-version", VERSION)
if body != nil {
req.Header.Set("Content-Type", "application/json")
}
resp, err := http.DefaultClient.Do(req)
if err != nil {
return nil, err
}
defer resp.Body.Close()
respBody, _ := io.ReadAll(resp.Body)
var data map[string]interface{}
json.Unmarshal(respBody, &data)
if !resp.Ok {
errMsg := string(respBody)
if len(errMsg) > 300 {
errMsg = errMsg[:300]
}
return nil, fmt.Errorf("%s %s failed (%d): %s", method, pathName, resp.StatusCode, errMsg)
}
return data, nil
}
func buildWorkflow() WorkflowRequest {
return WorkflowRequest{
Name: "Workers' Compensation Claim Summary Processing Pipeline",
Steps: []WorkflowStep{
{
Name: "startTrigger1",
Type: "TRIGGER",
Next: []map[string]string{{"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]bool{"enabled": true},
},
},
"chunkingStrategy": map[string]string{"type": "document"},
},
},
Next: []map[string]string{{"step": "extraction2"}},
},
{
Name: "extraction2",
Type: "EXTRACT",
Config: map[string]interface{}{
"extractorConfig": map[string]interface{}{
"schema": map[string]interface{}{
"type": "object",
"required": []string{"claims", "program", "employer", "date_printed", "valued_as_of"},
"properties": map[string]interface{}{
"claims": map[string]interface{}{
"type": "array",
"items": map[string]interface{}{
"type": "object",
"required": []string{"sdtf", "status", "surgery", "adjuster", "litigated", "longshore", "voc_rehab", "claim_type", "controvert", "date_hired", "financials", "fraudulent", "occupation", "settlement", "subrogated", "case_manager", "claim_number", "employee_ssn", "jurisdiction", "employee_name", "date_of_injury", "emp_report_date", "carrier_entry_date", "carrier_notify_date", "accident_description"},
"properties": map[string]interface{}{
"sdtf": map[string]interface{}{
"type": []string{"string", "null"},
"description": "Indicates whether the claim is associated with a Second Disability Trust Fund (SDTF) or similar. Typically 'Y' or 'N', but may vary.",
},
"status": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The current status of the claim, such as 'Open', 'Closed', or other status indicators. May be labeled as 'Status'.",
},
"surgery": map[string]interface{}{
"type": []string{"string", "null"},
"description": "Indicates whether surgery was performed as part of the claim. Typically 'Y' or 'N', but may vary.",
},
"adjuster": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The name or identifier of the adjuster assigned to this claim. May be labeled as 'Adjuster'.",
},
"litigated": map[string]interface{}{
"type": []string{"string", "null"},
"description": "Indicates whether the claim has entered litigation. Typically 'Y' or 'N', but may vary.",
},
"longshore": map[string]interface{}{
"type": []string{"string", "null"},
"description": "Indicates whether the claim is subject to Longshore and Harbor Workers' Compensation Act (LHWCA) or similar. Typically 'Y' or 'N', but may vary.",
},
"voc_rehab": map[string]interface{}{
"type": []string{"string", "null"},
"description": "Indicates whether vocational rehabilitation services were provided. Typically 'Y' or 'N', but may vary.",
},
"claim_type": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The type or category of the claim, such as 'Medical Only', 'Indemnity', 'Lost Time', etc. May be labeled as 'Claim Type'.",
},
"controvert": map[string]interface{}{
"type": []string{"string", "null"},
"description": "Indicates whether the claim is controverted or disputed. Typically 'Y' or 'N', but may vary.",
},
"date_hired": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The date the employee was hired by the employer. May be labeled as 'Date Hired'.",
"extend:type": "date",
},
"financials": map[string]interface{}{
"type": "object",
"required": []string{"total", "expense", "medical", "indemnity"},
"properties": map[string]interface{}{
"total": map[string]interface{}{
"type": "object",
"required": []string{"payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"},
"properties": map[string]interface{}{
"payments": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The total payments made to date on this claim.",
},
"recovery": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The total amount recovered on this claim.",
},
"reserves": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The total amount reserved for this claim.",
},
"net_incurred": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The total net incurred amount for this claim (reserves plus payments minus recoveries).",
},
"paid_this_month": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The total amount paid during the current month.",
},
"incurred_this_month": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The total amount incurred during the current month.",
},
},
"description": "Total financials for this claim, summing indemnity, medical, and expense categories.",
"additionalProperties": false,
},
"expense": map[string]interface{}{
"type": "object",
"required": []string{"payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"},
"properties": map[string]interface{}{
"payments": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The total expense payments made to date on this claim.",
},
"recovery": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The amount recovered for expenses on this claim.",
},
"reserves": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The amount reserved for expenses on this claim.",
},
"net_incurred": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The net incurred expense amount (reserves plus payments minus recoveries).",
},
"paid_this_month": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The expense amount paid during the current month.",
},
"incurred_this_month": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The expense amount incurred during the current month.",
},
},
"description": "Financial details for the expense portion of the claim.",
"additionalProperties": false,
},
"medical": map[string]interface{}{
"type": "object",
"required": []string{"payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"},
"properties": map[string]interface{}{
"payments": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The total medical payments made to date on this claim.",
},
"recovery": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The amount recovered for medical on this claim.",
},
"reserves": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The amount reserved for medical payments on this claim.",
},
"net_incurred": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The net incurred medical amount (reserves plus payments minus recoveries).",
},
"paid_this_month": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The medical amount paid during the current month.",
},
"incurred_this_month": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The medical amount incurred during the current month.",
},
},
"description": "Financial details for the medical portion of the claim.",
"additionalProperties": false,
},
"indemnity": map[string]interface{}{
"type": "object",
"required": []string{"payments", "recovery", "reserves", "net_incurred", "paid_this_month", "incurred_this_month"},
"properties": map[string]interface{}{
"payments": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The total indemnity payments made to date on this claim.",
},
"recovery": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The amount recovered for indemnity on this claim.",
},
"reserves": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The amount reserved for indemnity payments on this claim.",
},
"net_incurred": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The net incurred indemnity amount (reserves plus payments minus recoveries).",
},
"paid_this_month": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The indemnity amount paid during the current month.",
},
"incurred_this_month": map[string]interface{}{
"type": []string{"number", "null"},
"description": "The indemnity amount incurred during the current month.",
},
},
"description": "Financial details for indemnity (wage replacement) portion of the claim.",
"additionalProperties": false,
},
},
"description": "Summary of financial amounts associated with this claim, broken down by category such as indemnity, medical, and expense. Amounts may be shown as reserves, payments, recoveries, net incurred, and monthly values.",
"additionalProperties": false,
},
"fraudulent": map[string]interface{}{
"type": []string{"string", "null"},
"description": "Indicates whether the claim is suspected or confirmed as fraudulent. Typically 'Y' or 'N', but may vary.",
},
"occupation": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The job title or occupation of the employee at the time of the incident. May be labeled as 'Occupation'.",
},
"settlement": map[string]interface{}{
"type": []string{"string", "null"},
"description": "Indicates whether the claim has been settled. Typically 'Y' or 'N', but may vary.",
},
"subrogated": map[string]interface{}{
"type": []string{"string", "null"},
"description": "Indicates whether the claim is subrogated. Typically 'Y' or 'N', but may vary.",
},
"case_manager": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The name or identifier of the case manager handling this claim, if applicable.",
},
"claim_number": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The unique identifier assigned to this claim. May be labeled as 'Claim No.', 'Claim Number', or similar. Typically a numeric or alphanumeric value.",
},
"employee_ssn": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The Social Security Number or other unique identifier for the employee. May be partially redacted or omitted for privacy.",
},
"jurisdiction": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The legal jurisdiction or state where the claim is filed or administered. May be labeled as 'Jurisdiction'.",
},
"employee_name": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The name of the employee or claimant associated with this claim. May be labeled as 'Employee'.",
},
"date_of_injury": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The date on which the injury or incident occurred. May be labeled as 'DOI', 'Date of Injury', or similar.",
"extend:type": "date",
},
"emp_report_date": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The date the employee reported the incident or injury. May be labeled as 'Emp Report', 'Employee Reported', or similar.",
"extend:type": "date",
},
"carrier_entry_date": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The date the claim was entered into the carrier's system. May be labeled as 'Carrier Entry'.",
"extend:type": "date",
},
"carrier_notify_date": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The date the insurance carrier was notified of the claim. May be labeled as 'Carrier Notify'.",
"extend:type": "date",
},
"accident_description": map[string]interface{}{
"type": []string{"string", "null"},
"description": "A narrative or summary describing the circumstances of the accident or injury. May include details about what happened, how, and where.",
},
},
"additionalProperties": false,
},
"description": "A list of individual claims included in this loss run report. Each claim contains details about the incident, claimant, status, and financials. Claims may be presented in various layouts or formats.",
},
"program": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The insurance program, policy, or coverage type under which these claims are reported. May include program names, codes, or descriptions.",
},
"employer": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The name of the employer or insured entity for whom this loss run is generated. This is the organization covered by the policy.",
},
"date_printed": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The date on which this loss run report was generated or printed. This is the official date of the document and may be labeled as 'Date Printed', 'Report Date', or similar.",
"extend:type": "date",
},
"valued_as_of": map[string]interface{}{
"type": []string{"string", "null"},
"description": "The date as of which the values in this loss run are current. This is the valuation date for all claim data in the report. May be labeled as 'Valued As Of', 'As Of Date', or similar.",
"extend:type": "date",
},
},
"additionalProperties": false,
},
"baseProcessor": "extraction_performance",
"advancedOptions": map[string]interface{}{
"reviewAgent": map[string]bool{"enabled": true},
"advancedMultimodalEnabled": true,
},
},
},
},
},
}
}
func main() {
workflow := buildWorkflow()
fmt.Printf("Deploying \"%s\"…\n", workflow.Name)
if state.WorkflowID != "" {
fmt.Printf("✓ workflow already provisioned (%s) — updating steps\n", state.WorkflowID)
_, err := apiCall("POST", fmt.Sprintf("/workflows/%s", state.WorkflowID), map[string]interface{}{"steps": workflow.Steps})
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
} else {
// Try to find existing workflow by name
query := url.QueryEscape(workflow.Name)
list, err := apiCall("GET", fmt.Sprintf("/workflows?name=%s", query), nil)
var existing map[string]interface{}
if err == nil {
var items []map[string]interface{}
if data, ok := list["data"].([]interface{}); ok {
for _, v := range data {
items = append(items, v.(map[string]interface{}))
}
} else if data, ok := list["items"].([]interface{}); ok {
for _, v := range data {
items = append(items, v.(map[string]interface{}))
}
}
for _, item := range items {
if name, ok := item["name"].(string); ok && name == workflow.Name {
existing = item
break
}
}
}
if existing != nil && existing["id"] != nil {
state.WorkflowID = existing["id"].(string)
saveState()
fmt.Printf("✓ workflow \"%s\" found in your account (%s) — updating steps\n", workflow.Name, state.WorkflowID)
_, err := apiCall("POST", fmt.Sprintf("/workflows/%s", state.WorkflowID), map[string]interface{}{"steps": workflow.Steps})
if err != nil {
fmt.Fprintf(os.Stderr, "Error: %v\n", err)
os.Exit(1)
}
} else {
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 == "" {
fmt.Fprintln(os.Stderr, "Could not read created workflow id from response")
os.Exit(1)
}
state.WorkflowID = wfID
saveState()
fmt.Printf("+ created workflow (%s)\n", wfID)
}
}
// Deploy the current draft as a new version (best-effort)
apiCall("POST", fmt.Sprintf("/workflows/%s/versions", state.WorkflowID), map[string]interface{}{})
fmt.Println("\nDone. Run documents through it with:")
fmt.Printf(" POST %s/workflow_runs { workflow: { id: \"%s\" }, file: { url: \"https://…\" } }\n", API, state.WorkflowID)
fmt.Println("Or open the workflow in the Extend dashboard to review and deploy it.")
}This template processes Loss Run documents, capturing essential claim information including claim numbers, dates of injury, employee details, accident descriptions, and financial reserves and payments. It handles structured claim data with embedded tables showing cost breakdowns by category (medical, indemnity, expenses) and claim status indicators.