Financial & BankingSplit → Extract

Underwriting Package Splitter

Residential mortgage loan underwriting package with borrower documents and approval records.

Ship it with Extend

Live pipeline

a real document, processed end to end · view only
Source documentUnderwriting Package — Loan CSM-0084517.pdf

Step-by-step

An underwriting package contains all required documentation for loan approval and closing, including several documents such as certifications, tax returns, etc. This template takes in Underwriting Packages and outputs markdown (.md) capturing the document's full text and layout, and JSON (.json) with structured wage and tax fields including employee/employer identifiers, compensation amounts, and withholding details per the extraction schema. This is done after splitting the package into all of its sub-documents. by using Extend's Split, Extract primitives.

Input
Underwriting Packages
Compatible document types (full list)
.pdf.docx.xlsx.png.jpg.jpeg.tiff.tif.svg.heic.heif.bmp.gif.webp.psd.xls.xltm.xltx.ods.doc.wpd.dotx.odt.pptx.ppt.ppm.csv.txt.html.xml.rtf.lis.md.eml.pcx
Step 1

Split

Breaks a single file bundling multiple documents into separate, typed sub-documents.

InputBundled multi-document file, plus the expected document-type classifications
Config
splitClassifications45 document types definedchanged
OutputOne segment per detected sub-document — type, page range, and an independent file ID for downstream processing

You can learn more about Split configuration in Extend's Split documentation.

Step 2

Extract

Pulls a defined set of fields from the document and returns them as structured JSON matching a schema.

InputOutput of the Split step
Config
schemacustom schema — 30 fieldschanged
extractionRulesno custom rules
advancedOptions.advancedMultimodalEnabledfalse
advancedOptions.reviewAgent.enabledfalse
baseProcessor"extraction_performance"
OutputJSON shaped to the extraction schema, with per-field confidence scores and citations grounding each value to its source location

You can learn more about Extract configuration in Extend's Extract documentation.

Example code

{
  "name": "Underwriting Package Processing Pipeline",
  "steps": [
    {
      "name": "startTrigger1",
      "type": "TRIGGER",
      "next": [
        {
          "step": "parse1"
        }
      ]
    },
    {
      "name": "parse1",
      "type": "PARSE",
      "config": {
        "parseConfig": {
          "blockOptions": {
            "text": {
              "agentic": {
                "enabled": true
              },
              "signatureDetectionEnabled": true
            },
            "tables": {
              "agentic": {
                "enabled": true
              },
              "tableHeaderContinuationEnabled": true
            },
            "figures": {
              "enabled": true
            }
          },
          "chunkingStrategy": {
            "type": "page",
            "options": {}
          }
        }
      },
      "next": [
        {
          "step": "split2"
        }
      ]
    },
    {
      "name": "split2",
      "type": "SPLIT",
      "config": {
        "splitterConfig": {
          "splitClassifications": [
            {
              "id": "splitter_classification1",
              "type": "other",
              "description": "Use the `other` document type when the document can not clearly be classified into one of the described classifications."
            },
            {
              "id": "subdocument_type_45c",
              "type": "Loan Transmittal Cover Sheet",
              "description": "Cover page listing loan snapshot, borrower information, loan team, and package contents summary"
            },
            {
              "id": "subdocument_type_VxE",
              "type": "Uniform Underwriting and Transmittal Summary",
              "description": "Standardized form summarizing borrower income, mortgage information, qualifying ratios, and underwriter comments"
            },
            {
              "id": "subdocument_type_Cvy",
              "type": "Underwriting Approval Certificate",
              "description": "Official conditional approval document listing prior-to-document and prior-to-funding conditions with status"
            },
            {
              "id": "subdocument_type__MG",
              "type": "Automated Underwriting Findings",
              "description": "System-generated AUS findings report showing approve/eligible recommendation and risk assessment"
            },
            {
              "id": "subdocument_type_jHc",
              "type": "Uniform Residential Loan Application",
              "description": "Multi-page standard mortgage application with borrower employment, income, assets, liabilities, and property information"
            },
            {
              "id": "subdocument_type_4mW",
              "type": "Demographic Information Addendum",
              "description": "Government monitoring form capturing borrower race, ethnicity, and sex information"
            },
            {
              "id": "subdocument_type_zwe",
              "type": "Loan Estimate",
              "description": "Three page federal disclosure showing estimated loan terms, projected payments, and closing costs"
            },
            {
              "id": "subdocument_type_6cV",
              "type": "Closing Disclosure",
              "description": "Five page federal form showing final loan terms and itemized closing costs"
            },
            {
              "id": "subdocument_type_uC_",
              "type": "Intent to Proceed",
              "description": "Signed borrower acknowledgment of intent to proceed with loan application"
            },
            {
              "id": "subdocument_type_anp",
              "type": "Settlement Service Provider List",
              "description": "Written list of approved third party service providers"
            },
            {
              "id": "subdocument_type_R7E",
              "type": "ECOA Fair Lending Notice",
              "description": "Federal notice of equal credit opportunity rights and right to receive appraisal copy"
            },
            {
              "id": "subdocument_type_PcP",
              "type": "Homeownership Counseling Disclosure",
              "description": "List of HUD approved housing counseling organizations"
            },
            {
              "id": "subdocument_type_Qqj",
              "type": "Borrower Certification and Authorization",
              "description": "Borrower certification that application is accurate and authorization to verify information"
            },
            {
              "id": "subdocument_type_HgI",
              "type": "Tax Return Transcript Request",
              "description": "IRS form authorizing lender to obtain tax transcripts directly from IRS"
            },
            {
              "id": "subdocument_type_KmI",
              "type": "Residential Mortgage Credit Report",
              "description": "Tri-merge credit report showing credit history, scores, and tradelines from all three bureaus"
            },
            {
              "id": "subdocument_type_MDu",
              "type": "Credit Score Disclosure",
              "description": "Notice to home loan applicant disclosing credit scores used in underwriting decision"
            },
            {
              "id": "subdocument_type_Uog",
              "type": "Letter of Explanation",
              "description": "Borrower written explanation for credit inquiries or derogatory items"
            },
            {
              "id": "subdocument_type_aDh",
              "type": "Undisclosed Debt Monitoring Report",
              "description": "Soft pull credit refresh to identify any new debt incurred during loan process"
            },
            {
              "id": "subdocument_type_QSG",
              "type": "Earnings Statement / Pay Stub",
              "description": "Recent pay stub showing gross earnings, deductions, and year to date totals"
            },
            {
              "id": "subdocument_type_p8F",
              "type": "W-2 Wage and Tax Statement",
              "description": "Annual employer wage statement showing total compensation and withholdings"
            },
            {
              "id": "subdocument_type_hsN",
              "type": "Written Verification of Employment",
              "description": "Employer completed form verifying borrower employment, position, income, and start date"
            },
            {
              "id": "subdocument_type_6Wm",
              "type": "Verbal Verification of Employment",
              "description": "Lender log documenting phone verification of borrower employment status"
            },
            {
              "id": "subdocument_type_dMz",
              "type": "Tax Return Transcript",
              "description": "IRS transcript of filed tax return showing income, AGI, and withholdings"
            },
            {
              "id": "subdocument_type_6La",
              "type": "Income Calculation Worksheet",
              "description": "Underwriter worksheet documenting income calculation methodology and qualifying amounts"
            },
            {
              "id": "subdocument_type_aKJ",
              "type": "Bank Statement Checking",
              "description": "Monthly checking account statement showing transactions, deposits, and ending balance"
            },
            {
              "id": "subdocument_type_KRI",
              "type": "Bank Statement Savings",
              "description": "Monthly savings account statement showing deposits and ending balance"
            },
            {
              "id": "subdocument_type_6jD",
              "type": "Brokerage Statement",
              "description": "Investment account statement showing holdings, market value, and available assets"
            },
            {
              "id": "subdocument_type_KHi",
              "type": "Retirement Account Statement",
              "description": "401k or 403b statement showing account balance and vested amount"
            },
            {
              "id": "subdocument_type_K70",
              "type": "Gift Letter",
              "description": "Signed letter from donor documenting gift amount, relationship, and confirmation no repayment required"
            },
            {
              "id": "subdocument_type_h5y",
              "type": "Earnest Money Deposit Evidence",
              "description": "Documentation of earnest money deposit showing funds cleared from borrower account"
            },
            {
              "id": "subdocument_type_iPz",
              "type": "Uniform Residential Appraisal Report",
              "description": "Full appraisal report with property description, comparable sales, and appraised value"
            },
            {
              "id": "subdocument_type_yh5",
              "type": "UCDP Submission Summary Report",
              "description": "Appraisal portal submission confirmation showing document file ID and status"
            },
            {
              "id": "subdocument_type_Z-j",
              "type": "Appraisal Invoice",
              "description": "Invoice and delivery acknowledgment from appraisal management company"
            },
            {
              "id": "subdocument_type_-PC",
              "type": "Flood Hazard Determination",
              "description": "Life of loan flood zone certification showing flood zone classification"
            },
            {
              "id": "subdocument_type_VOq",
              "type": "Title Insurance Commitment",
              "description": "Commitment for title insurance with Schedule A property details and Schedule B exceptions"
            },
            {
              "id": "subdocument_type_On9",
              "type": "Closing Protection Letter",
              "description": "Letter extending title underwriter protection to lender for closing agent acts"
            },
            {
              "id": "subdocument_type_UEl",
              "type": "Wire and Disbursement Instructions",
              "description": "Escrow agent wire instructions for funding disbursement"
            },
            {
              "id": "subdocument_type_0_8",
              "type": "Homeowners Insurance Declaration Page",
              "description": "Insurance policy declarations showing coverage amounts, premium, and mortgagee clause"
            },
            {
              "id": "subdocument_type_dZ3",
              "type": "Flood Insurance Exemption Notice",
              "description": "Lender notice that flood insurance is not required based on flood zone determination"
            },
            {
              "id": "subdocument_type_PBZ",
              "type": "Residential Purchase and Sale Agreement",
              "description": "Executed contract between buyer and seller including purchase price, terms, and contingencies"
            },
            {
              "id": "subdocument_type_2br",
              "type": "Seller Disclosure Notice",
              "description": "Seller's written disclosure of known property condition issues"
            },
            {
              "id": "subdocument_type_MO6",
              "type": "Verification of Rent",
              "description": "Documentation of borrower's current housing payment history"
            },
            {
              "id": "subdocument_type_Dgl",
              "type": "Government Photo ID",
              "description": "Copies of borrower government issued photo identification per USA PATRIOT Act requirements"
            },
            {
              "id": "subdocument_type_w1k",
              "type": "Loan Officer Compensation Disclosure",
              "description": "Anti-steering and loan officer compensation disclosure form"
            }
          ]
        }
      },
      "next": [
        {
          "step": "extraction3",
          "classificationId": "splitter_classification1"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_45c"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_VxE"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_Cvy"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type__MG"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_jHc"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_4mW"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_zwe"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_6cV"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_uC_"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_anp"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_R7E"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_PcP"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_Qqj"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_HgI"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_KmI"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_MDu"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_Uog"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_aDh"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_QSG"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_p8F"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_hsN"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_6Wm"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_dMz"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_6La"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_aKJ"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_KRI"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_6jD"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_KHi"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_K70"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_h5y"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_iPz"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_yh5"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_Z-j"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_-PC"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_VOq"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_On9"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_UEl"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_0_8"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_dZ3"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_PBZ"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_2br"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_MO6"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_Dgl"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_w1k"
        }
      ]
    },
    {
      "name": "extraction3",
      "type": "EXTRACT",
      "config": {
        "extractorConfig": {
          "schema": {
            "type": "object",
            "required": [
              "state",
              "tax_year",
              "box_12_codes",
              "employee_name",
              "employer_name",
              "locality_name",
              "allocated_tips",
              "control_number",
              "retirement_plan",
              "employee_address",
              "employer_address",
              "local_income_tax",
              "state_income_tax",
              "other_information",
              "nonqualified_plans",
              "statutory_employee",
              "local_wages_tips_etc",
              "social_security_tips",
              "state_wages_tips_etc",
              "third_party_sick_pay",
              "medicare_tax_withheld",
              "social_security_wages",
              "wages_tips_other_comp",
              "dependent_care_benefits",
              "medicare_wages_and_tips",
              "employer_state_id_number",
              "federal_income_tax_withheld",
              "social_security_tax_withheld",
              "employer_identification_number",
              "employee_social_security_number"
            ],
            "properties": {
              "state": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The state in which the employer is located or where state wages and taxes are reported. May be labeled as 'State' or appear with the employer's address."
              },
              "tax_year": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The calendar year for which this wage and tax statement applies. This is the reporting year for the income and withholdings shown. Commonly appears as part of the document title or heading."
              },
              "box_12_codes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "code",
                    "amount",
                    "description"
                  ],
                  "properties": {
                    "code": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The single-letter or letter-number code used in Box 12 to indicate the type of compensation, deferral, or benefit (e.g., D, E, AA, etc.)."
                    },
                    "amount": {
                      "type": [
                        "number",
                        "null"
                      ],
                      "description": "The monetary value or amount associated with this Box 12 code, if applicable."
                    },
                    "description": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "A brief description of what the code represents, if available. May be present in document footnotes or instructions."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "An array of code-value pairs reported in Box 12. Each entry represents a specific code (such as D, E, etc.) and the corresponding amount or value. These codes report various types of compensation, deferrals, or benefits. The codes and their meanings may vary by year and employer."
              },
              "employee_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The full legal name of the employee as reported on the wage and tax statement. Typically includes first name, middle initial, and last name, and may include suffixes. Commonly found near the employee's address."
              },
              "employer_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The legal name of the employer or company issuing this wage and tax statement. This is the entity that paid the employee and is responsible for reporting wages and withholdings."
              },
              "locality_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The name of the locality (city, county, or other jurisdiction) for which local wages and taxes are reported. May be labeled as 'Locality name' or 'Box 20'."
              },
              "allocated_tips": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The amount of tips allocated to the employee by the employer, if applicable. May be labeled as 'Allocated tips' or 'Box 8'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "control_number": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "A unique control or reference number assigned to this wage and tax statement by the employer or payroll processor. Used for internal tracking and may appear as 'Control number' or similar."
              },
              "retirement_plan": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Indicates whether the employee was an active participant in an employer-sponsored retirement plan during the tax year. This is typically marked as a checkbox or indicator."
              },
              "employee_address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The mailing address of the employee as reported on the wage and tax statement. May include street address, unit/apartment, city, state, and ZIP code. Can span multiple lines in some documents."
              },
              "employer_address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The mailing address of the employer as reported on the wage and tax statement. May include street address, suite or unit, city, state, and ZIP code. Can span multiple lines."
              },
              "local_income_tax": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of local income tax withheld from the employee's pay for the tax year. May be labeled as 'Local income tax' or 'Box 19'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "state_income_tax": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of state income tax withheld from the employee's pay for the tax year. May be labeled as 'State income tax' or 'Box 17'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "other_information": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Any additional information or miscellaneous codes reported in Box 14 or similar sections. This may include state-specific codes, explanations, or other employer-provided notes."
              },
              "nonqualified_plans": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount distributed to the employee from nonqualified deferred compensation plans. May be labeled as 'Nonqualified plans' or 'Box 11'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "statutory_employee": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Indicates whether the employee is classified as a statutory employee for tax purposes. This is typically marked as a checkbox or indicator on the wage and tax statement."
              },
              "local_wages_tips_etc": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of wages, tips, and other compensation subject to local income tax for the tax year. May be labeled as 'Local wages, tips, etc.' or 'Box 18'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "social_security_tips": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total tips reported by the employee that are subject to Social Security tax. May be labeled as 'Social security tips' or 'Box 7'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "state_wages_tips_etc": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of wages, tips, and other compensation subject to state income tax for the tax year. May be labeled as 'State wages, tips, etc.' or 'Box 16'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "third_party_sick_pay": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Indicates whether the employee received third-party sick pay during the tax year. This is typically marked as a checkbox or indicator."
              },
              "medicare_tax_withheld": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of Medicare tax withheld from the employee's pay for the tax year. Often labeled as 'Medicare tax withheld' or 'Box 6'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "social_security_wages": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total wages subject to Social Security tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Social security wages' or 'Box 3'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "wages_tips_other_comp": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total taxable wages, tips, and other compensation paid to the employee for the tax year. This is the primary income amount reported for federal tax purposes, often labeled as 'Wages, tips, other comp.' or 'Box 1'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "dependent_care_benefits": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of dependent care benefits provided to the employee, if any. May be labeled as 'Dependent care benefits' or 'Box 10'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "medicare_wages_and_tips": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total wages and tips subject to Medicare tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Medicare wages and tips' or 'Box 5'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "employer_state_id_number": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The employer's state identification number as reported on the wage and tax statement. This is used for state tax reporting and may be labeled as 'Employer's state ID no.' or similar."
              },
              "federal_income_tax_withheld": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of federal income tax withheld from the employee's pay for the tax year. This is the sum reported to the federal tax authority, often labeled as 'Federal income tax withheld' or 'Box 2'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "social_security_tax_withheld": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of Social Security tax withheld from the employee's pay for the tax year. Often labeled as 'Social security tax withheld' or 'Box 4'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "employer_identification_number": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The employer's federal Employer Identification Number (EIN), a nine-digit number often formatted as XX-XXXXXXX. Used for tax reporting purposes."
              },
              "employee_social_security_number": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The employee's Social Security Number (SSN) as reported on the wage and tax statement. This is a nine-digit identifier, often formatted as XXX-XX-XXXX. May be labeled as 'Employee's social security number' or similar."
              }
            },
            "additionalProperties": false
          },
          "baseProcessor": "extraction_performance",
          "advancedOptions": {
            "reviewAgent": {
              "enabled": false
            },
            "advancedMultimodalEnabled": false
          }
        }
      }
    }
  ]
}
# Underwriting Package Processing — Extend AI Skill

## What this pipeline does

This pipeline processes residential mortgage underwriting packages by parsing the entire bundle, splitting it into 47 distinct document types (loan transmittal, application, appraisal, disclosures, financial statements, etc.), and extracting W-2 wage and tax statement fields from identified W-2 documents. Input: a single PDF bundle (20–100+ pages). Output: structured JSON with document classifications, page ranges, and W-2 field extraction for qualifying income verification.

## When to use this

- **Mortgage loan origination & underwriting automation** — split incoming packages into standardized components for rapid document routing and compliance review.
- **Income verification workflows** — automatically locate and extract W-2 tax data from mixed underwriting packages without manual document identification.
- **Compliance & quality assurance** — ensure all required document types are present before moving to next underwriting stage; flag missing disclosures or certifications.
- **Multi-borrower packages** — handle co-borrower applications with multiple W-2s, employment verifications, and asset statements in one ingestion.
- **Batch loan portfolio processing** — scale document intake across hundreds of loans per day with consistent taxonomy and error-free routing.

## Processor pipeline

### Step 1: Parse (agentic OCR + signature detection)
**Processor:** `PARSE` with agentic OCR, signature detection, table headers, figures enabled  
**Purpose:** Convert PDF pages into clean markdown with bounding boxes, detect signed acknowledgments, extract tabular data (income worksheets, credit reports).  
**Why this config:**
- `agentic: true` on text & tables — handles mixed layouts (scans, handwriting, form overlays) common in underwriting packages
- `signatureDetectionEnabled: true` — critical for compliance: verify borrower certification, authorization, and intent-to-proceed signatures
- `tableHeaderContinuation: true` — mortgage documents span multi-page tables (credit report tradelines, asset accounts); headers must repeat for OCR accuracy
- `chunkingStrategy: "page"` — one chunk per page preserves document flow and makes split classification deterministic

### Step 2: Split (47-type classification)
**Processor:** `SPLIT` with 47 document type classifications  
**Purpose:** Break the unified package into sub-documents, routing each to correct downstream system (e.g., appraisal QA, compliance filing, income verification).  
**Why this config:**
- **Standardized taxonomy** — all 47 types aligned to Freddie Mac/Fannie Mae underwriting standards (Uniform Residential Loan Application, Closing Disclosure, etc.)
- **Conditional routing** — each split output feeds to extraction step *only if* that document is W-2 (subdocument_type_p8F); others pass through for downstream processing
- **Catch-all "other"** — unknown or blank pages don't crash; routed to manual review queue
- **Precision descriptions** — each classifier type has explicit purpose statement; agentic OCR leverages context (e.g., "Standardized form summarizing borrower income" → targets UUTS)

### Step 3: Extract (W-2 fields from identified documents)
**Processor:** `EXTRACT` with `extraction_performance` (highest accuracy) + W-2 schema  
**Purpose:** From documents classified as "W-2 Wage and Tax Statement," pull all 31 required fields (boxes 1–19, employee/employer identifiers, Box 12 codes array).  
**Why this config:**
- `baseProcessor: extraction_performance` — W-2 forms are low-variability, standardized IRS documents; performance mode balances speed and accuracy (vs. light mode which trades accuracy)
- **Currency fields** — all tax withholding amounts use `extendCurrency()` (amount + ISO 4217 code) for accounting system integration
- **Array support** — Box 12 codes vary by employer (D, E, AA, DD); schema captures multiple code–amount pairs
- **Nullable strategically** — most fields nullable (employers may omit Box 11 nonqualified plans); required array is empty for w-2s without Box 12 codes
- **Schema descriptions** — each field includes label alternatives (e.g., "Box 1" vs. "Wages, tips, other comp") so extraction handles scanned + digital PDFs

## TypeScript implementation

<SDK_CODE>
import fs from "fs";
import { ExtendClient, extendCurrency, extendDate } from "extend-ai";
import { z } from "zod";

const client = new ExtendClient({ token: process.env.EXTEND_API_KEY });

// Zod schema for W-2 extraction (mapped from underwriting package workflow)
const w2Schema = z.object({
  state: z.string().nullable().describe("State where employer located or state wages reported"),
  tax_year: z.string().nullable().describe("Calendar year for wage and tax statement"),
  box_12_codes: z.array(
    z.object({
      code: z.string().nullable().describe("Single-letter or letter-number code (D, E, AA, etc.)"),
      amount: z.number().nullable().describe("Monetary value associated with code"),
      description: z.string().nullable().describe("Brief description of code from document or IRS instructions"),
    })
  ).describe("Array of Box 12 code-value pairs for various compensation types"),
  employee_name: z.string().nullable().describe("Full legal name of employee"),
  employer_name: z.string().nullable().describe("Legal name of employer issuing statement"),
  locality_name: z.string().nullable().describe("City, county, or jurisdiction for local tax reporting"),
  allocated_tips: extendCurrency().describe("Tips allocated by employer (Box 8)"),
  control_number: z.string().nullable().describe("Unique control number from employer or payroll processor"),
  retirement_plan: z.boolean().nullable().describe("Active participant in employer retirement plan"),
  employee_address: z.string().nullable().describe("Employee mailing address (street, city, state, ZIP)"),
  employer_address: z.string().nullable().describe("Employer mailing address"),
  local_income_tax: extendCurrency().describe("Local income tax withheld (Box 19)"),
  state_income_tax: extendCurrency().describe("State income tax withheld (Box 17)"),
  other_information: z.string().nullable().describe("Box 14 or miscellaneous codes and notes"),
  nonqualified_plans: extendCurrency().describe("Nonqualified deferred compensation (Box 11)"),
  statutory_employee: z.boolean().nullable().describe("Statutory employee classification for tax purposes"),
  local_wages_tips_etc: extendCurrency().describe("Wages, tips, other compensation subject to local tax (Box 18)"),
  social_security_tips: extendCurrency().describe("Tips subject to Social Security tax (Box 7)"),
  state_wages_tips_etc: extendCurrency().describe("Wages, tips, other compensation subject to state tax (Box 16)"),
  third_party_sick_pay: z.boolean().nullable().describe("Received third-party sick pay during tax year"),
  medicare_tax_withheld: extendCurrency().describe("Medicare tax withheld (Box 6)"),
  social_security_wages: extendCurrency().describe("Wages subject to Social Security tax (Box 3)"),
  wages_tips_other_comp: extendCurrency().describe("Total taxable wages, tips, other compensation (Box 1)"),
  dependent_care_benefits: extendCurrency().describe("Dependent care benefits provided (Box 10)"),
  medicare_wages_and_tips: extendCurrency().describe("Wages and tips subject to Medicare tax (Box 5)"),
  employer_state_id_number: z.string().nullable().describe("Employer state identification number"),
  federal_income_tax_withheld: extendCurrency().describe("Federal income tax withheld (Box 2)"),
  social_security_tax_withheld: extendCurrency().describe("Social Security tax withheld (Box 4)"),
  employer_identification_number: z.string().nullable().describe("Employer EIN (XX-XXXXXXX format)"),
  employee_social_security_number: z.string().nullable().describe("Employee SSN (XXX-XX-XXXX format)"),
});

async function processUnderwritingPackage(filePath: string) {
  console.log(`[1/3] Uploading underwriting package: ${filePath}`);

  // Convert local file to base64 data URL for SDK upload
  const fileData = fs.readFileSync(filePath);
  const dataUrl = `data:application/octet-stream;base64,${fileData.toString("base64")}`;

  // Step 1: Parse the entire underwriting package
  console.log("[2/3] Parsing package (agentic OCR, signature detection)...");
  const parseRun = await client.parseRuns.createAndPoll({
    file: { url: dataUrl },
  });

  if (parseRun.status !== "PROCESSED") {
    throw new Error(`Parse failed: ${parseRun.status}`);
  }

  console.log(`  ✓ Parsed ${parseRun.output?.chunks?.length ?? 0} page chunks`);

  // Step 2: Split into 47 document types
  console.log("[3/3] Splitting into document types and extracting W-2 fields...");

  const splitClassifications = [
    { id: "splitter_classification1", type: "other", description: "Use the `other` document type when the document can not clearly be classified into one of the described classifications." },
    { id: "subdocument_type_45c", type: "Loan Transmittal Cover Sheet", description: "Cover page listing loan snapshot, borrower information, loan team, and package contents summary" },
    { id: "subdocument_type_VxE", type: "Uniform Underwriting and Transmittal Summary", description: "Standardized form summarizing borrower income, mortgage information, qualifying ratios, and underwriter comments" },
    { id: "subdocument_type_Cvy", type: "Underwriting Approval Certificate", description: "Official conditional approval document listing prior-to-document and prior-to-funding conditions with status" },
    { id: "subdocument_type__MG", type: "Automated Underwriting Findings", description: "System-generated AUS findings report showing approve/eligible recommendation and risk assessment" },
    { id: "subdocument_type_jHc", type: "Uniform Residential Loan Application", description: "Multi-page standard mortgage application with borrower employment, income, assets, liabilities, and property information" },
    { id: "subdocument_type_4mW", type: "Demographic Information Addendum", description: "Government monitoring form capturing borrower race, ethnicity, and sex information" },
    { id: "subdocument_type_zwe", type: "Loan Estimate", description: "Three page federal disclosure showing estimated loan terms, projected payments, and closing costs" },
    { id: "subdocument_type_6cV", type: "Closing Disclosure", description: "Five page federal form showing final loan terms and itemized closing costs" },
    { id: "subdocument_type_uC_", type: "Intent to Proceed", description: "Signed borrower acknowledgment of intent to proceed with loan application" },
    { id: "subdocument_type_anp", type: "Settlement Service Provider List", description: "Written list of approved third party service providers" },
    { id: "subdocument_type_R7E", type: "ECOA Fair Lending Notice", description: "Federal notice of equal credit opportunity rights and right to receive appraisal copy" },
    { id: "subdocument_type_PcP", type: "Homeownership Counseling Disclosure", description: "List of HUD approved housing counseling organizations" },
    { id: "subdocument_type_Qqj", type: "Borrower Certification and Authorization", description: "Borrower certification that application is accurate and authorization to verify information" },
    { id: "subdocument_type_HgI", type: "Tax Return Transcript Request", description: "IRS form authorizing lender to obtain tax transcripts directly from IRS" },
    { id: "subdocument_type_KmI", type: "Residential Mortgage Credit Report", description: "Tri-merge credit report showing credit history, scores, and tradelines from all three bureaus" },
    { id: "subdocument_type_MDu", type: "Credit Score Disclosure", description: "Notice to home loan applicant disclosing credit scores used in underwriting decision" },
    { id: "subdocument_type_Uog", type: "Letter of Explanation", description: "Borrower written explanation for credit inquiries or derogatory items" },
    { id: "subdocument_type_aDh", type: "Undisclosed Debt Monitoring Report", description: "Soft pull credit refresh to identify any new debt incurred during loan process" },
    { id: "subdocument_type_QSG", type: "Earnings Statement / Pay Stub", description: "Recent pay stub showing gross earnings, deductions, and year to date totals" },
    { id: "subdocument_type_p8F", type: "W-2 Wage and Tax Statement", description: "Annual employer wage statement showing total compensation and withholdings" },
    { id: "subdocument_type_hsN", type: "Written Verification of Employment", description: "Employer completed form verifying borrower employment, position, income, and start date" },
    { id: "subdocument_type_6Wm", type: "Verbal Verification of Employment", description: "Lender log documenting phone verification of borrower employment status" },
    { id: "subdocument_type_dMz", type: "Tax Return Transcript", description: "IRS transcript of filed tax return showing income, AGI, and withholdings" },
    { id: "subdocument_type_6La", type: "Income Calculation Worksheet", description: "Underwriter worksheet documenting income calculation methodology and qualifying amounts" },
    { id: "subdocument_type_aKJ", type: "Bank Statement Checking", description: "Monthly checking account statement showing transactions, deposits, and ending balance" },
    { id: "subdocument_type_KRI", type: "Bank Statement Savings", description: "Monthly savings account statement showing deposits and ending balance" },
    { id: "subdocument_type_6jD", type: "Brokerage Statement", description: "Investment account statement showing holdings, market value, and available assets" },
    { id: "subdocument_type_KHi", type: "Retirement Account Statement", description: "401k or 403b statement showing account balance and vested amount" },
    { id: "subdocument_type_K70", type: "Gift Letter", description: "Signed letter from donor documenting gift amount, relationship, and confirmation no repayment required" },
    { id: "subdocument_type_h5y", type: "Earnest Money Deposit Evidence", description: "Documentation of earnest money deposit showing funds cleared from borrower account" },
    { id: "subdocument_type_iPz", type: "Uniform Residential Appraisal Report", description: "Full appraisal report with property description, comparable sales, and appraised value" },
    { id: "subdocument_type_yh5", type: "UCDP Submission Summary Report", description: "Appraisal portal submission confirmation showing document file ID and status" },
    { id: "subdocument_type_Z-j", type: "Appraisal Invoice", description: "Invoice and delivery acknowledgment from appraisal management company" },
    { id: "subdocument_type_-PC", type: "Flood Hazard Determination", description: "Life of loan flood zone certification showing flood zone classification" },
    { id: "subdocument_type_VOq", type: "Title Insurance Commitment", description: "Commitment for title insurance with Schedule A property details and Schedule B exceptions" },
    { id: "subdocument_type_On9", type: "Closing Protection Letter", description: "Letter extending title underwriter protection to lender for closing agent acts" },
    { id: "subdocument_type_UEl", type: "Wire and Disbursement Instructions", description: "Escrow agent wire instructions for funding disbursement" },
    { id: "subdocument_type_0_8", type: "Homeowners Insurance Declaration Page", description: "Insurance policy declarations showing coverage amounts, premium, and mortgagee clause" },
    { id: "subdocument_type_dZ3", type: "Flood Insurance Exemption Notice", description: "Lender notice that flood insurance is not required based on flood zone determination" },
    { id: "
import { ExtendClient, extendCurrency } from "extend-ai";
import { z } from "zod";
import fs from "fs";
import path from "path";

const client = new ExtendClient({ token: process.env.EXTEND_API_KEY });

// Define the extraction schema using Zod
const underwritingPackageSchema = z.object({
  lender_name: z.string().nullable().describe(
    "Name of the lending institution (e.g., 'Cascade Summit Mortgage, LLC')"
  ),
  lender_address: z.string().nullable().describe(
    "Complete mailing address of the lender including street, city, state, ZIP"
  ),
  nmls_number: z.string().nullable().describe(
    "NMLS identifier for the lender (numeric, often prefixed with #)"
  ),
  loan_number: z.string().nullable().describe(
    "Unique loan identification number assigned by the lender (e.g., 'CSM-0084517')"
  ),
  assembly_date: z.string().nullable().describe(
    "Date the underwriting package was assembled in YYYY-MM-DD format"
  ),
  borrowers: z.string().nullable().describe(
    "Names of primary borrower and co-borrowers, separated by commas or 'and'"
  ),
  subject_property_address: z.string().nullable().describe(
    "Physical street address of the subject property (the property being financed)"
  ),
  loan_type: z.string().nullable().describe(
    "Type and term of loan (e.g., 'Conventional 30-Year Fixed', 'FHA 15-Year', 'VA ARM')"
  ),
  loan_amount: z.string().nullable().describe(
    "Principal loan amount in USD (e.g., '$350,000.00' or '350000')"
  ),
  package_structure: z.string().nullable().describe(
    "Summary of package composition: list of document types included (e.g., '1) Loan Application, 2) Pay Stubs, 3) Tax Returns, 4) Appraisal, 5) Title Report')"
  ),
  total_pages: z.string().nullable().describe(
    "Total number of pages in the underwriting package (numeric string)"
  ),
  total_documents: z.string().nullable().describe(
    "Total number of distinct documents included in the package (numeric string)"
  ),
});

type UnderwritingPackageData = z.infer<typeof underwritingPackageSchema>;

/**
 * Main entry point: parse and extract underwriting package metadata
 * @param filePath - Local file path to the underwriting package PDF
 */
export async function processUnderwritingPackage(
  filePath: string
): Promise<UnderwritingPackageData> {
  console.log(`[Underwriting Package] Processing: ${filePath}`);

  // Read file and convert to data URL (base64)
  const fileBuffer = fs.readFileSync(filePath);
  const base64 = fileBuffer.toString("base64");
  const mimeType = "application/pdf";
  const dataUrl = `data:${mimeType};base64,${base64}`;

  // Step 1: Parse the document to markdown
  console.log("[Step 1/2] Parsing document structure and content...");
  const parseRun = await client.parseRuns.createAndPoll({
    file: { url: dataUrl },
    config: {
      mode: "agentic_ocr",
      outputType: "markdown",
    },
  });

  if (parseRun.status !== "PROCESSED") {
    throw new Error(`Parse failed with status: ${parseRun.status}`);
  }

  // Log parsed content for debugging
  const parsedContent = parseRun.output.chunks
    .map((chunk) => chunk.content)
    .join("\n\n");
  console.log(`[Parsed] ${parseRun.output.chunks.length} chunks extracted`);
  console.log(`[Sample] ${parsedContent.substring(0, 200)}...`);

  // Step 2: Extract structured fields
  console.log("[Step 2/2] Extracting structured fields...");
  const extractRun = await client.extractRuns.createAndPoll({
    file: { url: dataUrl },
    config: {
      schema: underwritingPackageSchema,
      baseProcessor: "extraction_performance",
    },
  });

  if (extractRun.status !== "PROCESSED") {
    throw new Error(`Extract failed with status: ${extractRun.status}`);
  }

  const extracted = extractRun.output.value as UnderwritingPackageData;

  // Log results
  console.log("\n[Results] Underwriting Package Metadata:");
  console.log(`  Lender: ${extracted.lender_name}`);
  console.log(`  Loan Number: ${extracted.loan_number}`);
  console.log(`  Loan Amount: ${extracted.loan_amount}`);
  console.log(`  Loan Type: ${extracted.loan_type}`);
  console.log(`  Assembly Date: ${extracted.assembly_date}`);
  console.log(`  Borrowers: ${extracted.borrowers}`);
  console.log(`  Property: ${extracted.subject_property_address}`);
  console.log(`  NMLS: ${extracted.nmls_number}`);
  console.log(`  Total Pages: ${extracted.total_pages}`);
  console.log(`  Total Documents: ${extracted.total_documents}`);
  console.log(`  Package Structure: ${extracted.package_structure}`);

  return extracted;
}

// Auto-invoke if run directly with a file path argument
const args = process.argv.slice(2);
if (args.length > 0) {
  const filePath = args[0];
  if (!fs.existsSync(filePath)) {
    console.error(`File not found: ${filePath}`);
    process.exit(1);
  }
  processUnderwritingPackage(filePath)
    .then((result) => {
      console.log("\n[Success] Extraction complete.");
      console.log(JSON.stringify(result, null, 2));
    })
    .catch((err) => {
      console.error("[Error]", err.message);
      process.exit(1);
    });
}
import os
import sys
from typing import TypedDict, Optional, List
from extend_ai import Extend

client = Extend(token=os.environ["EXTEND_API_KEY"])


class Box12Code(TypedDict):
    code: Optional[str]
    amount: Optional[float]
    description: Optional[str]


class CurrencyAmount(TypedDict):
    amount: Optional[float]
    iso_4217_currency_code: Optional[str]


class W2FormData(TypedDict):
    state: Optional[str]
    tax_year: Optional[str]
    box_12_codes: List[Box12Code]
    employee_name: Optional[str]
    employer_name: Optional[str]
    locality_name: Optional[str]
    allocated_tips: CurrencyAmount
    control_number: Optional[str]
    retirement_plan: Optional[bool]
    employee_address: Optional[str]
    employer_address: Optional[str]
    local_income_tax: CurrencyAmount
    state_income_tax: CurrencyAmount
    other_information: Optional[str]
    nonqualified_plans: CurrencyAmount
    statutory_employee: Optional[bool]
    local_wages_tips_etc: CurrencyAmount
    social_security_tips: CurrencyAmount
    state_wages_tips_etc: CurrencyAmount
    third_party_sick_pay: Optional[bool]
    medicare_tax_withheld: CurrencyAmount
    social_security_wages: CurrencyAmount
    wages_tips_other_comp: CurrencyAmount
    dependent_care_benefits: CurrencyAmount
    medicare_wages_and_tips: CurrencyAmount
    employer_state_id_number: Optional[str]
    federal_income_tax_withheld: CurrencyAmount
    social_security_tax_withheld: CurrencyAmount
    employer_identification_number: Optional[str]
    employee_social_security_number: Optional[str]


extraction_schema = {
    "type": "object",
    "required": [
        "state",
        "tax_year",
        "box_12_codes",
        "employee_name",
        "employer_name",
        "locality_name",
        "allocated_tips",
        "control_number",
        "retirement_plan",
        "employee_address",
        "employer_address",
        "local_income_tax",
        "state_income_tax",
        "other_information",
        "nonqualified_plans",
        "statutory_employee",
        "local_wages_tips_etc",
        "social_security_tips",
        "state_wages_tips_etc",
        "third_party_sick_pay",
        "medicare_tax_withheld",
        "social_security_wages",
        "wages_tips_other_comp",
        "dependent_care_benefits",
        "medicare_wages_and_tips",
        "employer_state_id_number",
        "federal_income_tax_withheld",
        "social_security_tax_withheld",
        "employer_identification_number",
        "employee_social_security_number",
    ],
    "properties": {
        "state": {
            "type": ["string", "null"],
            "description": "The state in which the employer is located or where state wages and taxes are reported. May be labeled as 'State' or appear with the employer's address.",
        },
        "tax_year": {
            "type": ["string", "null"],
            "description": "The calendar year for which this wage and tax statement applies. This is the reporting year for the income and withholdings shown. Commonly appears as part of the document title or heading.",
        },
        "box_12_codes": {
            "type": "array",
            "items": {
                "type": "object",
                "required": ["code", "amount", "description"],
                "properties": {
                    "code": {
                        "type": ["string", "null"],
                        "description": "The single-letter or letter-number code used in Box 12 to indicate the type of compensation, deferral, or benefit (e.g., D, E, AA, etc.).",
                    },
                    "amount": {
                        "type": ["number", "null"],
                        "description": "The monetary value or amount associated with this Box 12 code, if applicable.",
                    },
                    "description": {
                        "type": ["string", "null"],
                        "description": "A brief description of what the code represents, if available. May be present in document footnotes or instructions.",
                    },
                },
                "additionalProperties": False,
            },
            "description": "An array of code-value pairs reported in Box 12. Each entry represents a specific code (such as D, E, etc.) and the corresponding amount or value. These codes report various types of compensation, deferrals, or benefits. The codes and their meanings may vary by year and employer.",
        },
        "employee_name": {
            "type": ["string", "null"],
            "description": "The full legal name of the employee as reported on the wage and tax statement. Typically includes first name, middle initial, and last name, and may include suffixes. Commonly found near the employee's address.",
        },
        "employer_name": {
            "type": ["string", "null"],
            "description": "The legal name of the employer or company issuing this wage and tax statement. This is the entity that paid the employee and is responsible for reporting wages and withholdings.",
        },
        "locality_name": {
            "type": ["string", "null"],
            "description": "The name of the locality (city, county, or other jurisdiction) for which local wages and taxes are reported. May be labeled as 'Locality name' or 'Box 20'.",
        },
        "allocated_tips": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The amount of tips allocated to the employee by the employer, if applicable. May be labeled as 'Allocated tips' or 'Box 8'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "control_number": {
            "type": ["string", "null"],
            "description": "A unique control or reference number assigned to this wage and tax statement by the employer or payroll processor. Used for internal tracking and may appear as 'Control number' or similar.",
        },
        "retirement_plan": {
            "type": ["boolean", "null"],
            "description": "Indicates whether the employee was an active participant in an employer-sponsored retirement plan during the tax year. This is typically marked as a checkbox or indicator.",
        },
        "employee_address": {
            "type": ["string", "null"],
            "description": "The mailing address of the employee as reported on the wage and tax statement. May include street address, unit/apartment, city, state, and ZIP code. Can span multiple lines in some documents.",
        },
        "employer_address": {
            "type": ["string", "null"],
            "description": "The mailing address of the employer as reported on the wage and tax statement. May include street address, suite or unit, city, state, and ZIP code. Can span multiple lines.",
        },
        "local_income_tax": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total amount of local income tax withheld from the employee's pay for the tax year. May be labeled as 'Local income tax' or 'Box 19'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "state_income_tax": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total amount of state income tax withheld from the employee's pay for the tax year. May be labeled as 'State income tax' or 'Box 17'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "other_information": {
            "type": ["string", "null"],
            "description": "Any additional information or miscellaneous codes reported in Box 14 or similar sections. This may include state-specific codes, explanations, or other employer-provided notes.",
        },
        "nonqualified_plans": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total amount distributed to the employee from nonqualified deferred compensation plans. May be labeled as 'Nonqualified plans' or 'Box 11'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "statutory_employee": {
            "type": ["boolean", "null"],
            "description": "Indicates whether the employee is classified as a statutory employee for tax purposes. This is typically marked as a checkbox or indicator on the wage and tax statement.",
        },
        "local_wages_tips_etc": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total amount of wages, tips, and other compensation subject to local income tax for the tax year. May be labeled as 'Local wages, tips, etc.' or 'Box 18'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "social_security_tips": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total tips reported by the employee that are subject to Social Security tax. May be labeled as 'Social security tips' or 'Box 7'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "state_wages_tips_etc": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total amount of wages, tips, and other compensation subject to state income tax for the tax year. May be labeled as 'State wages, tips, etc.' or 'Box 16'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "third_party_sick_pay": {
            "type": ["boolean", "null"],
            "description": "Indicates whether the employee received third-party sick pay during the tax year. This is typically marked as a checkbox or indicator.",
        },
        "medicare_tax_withheld": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total amount of Medicare tax withheld from the employee's pay for the tax year. Often labeled as 'Medicare tax withheld' or 'Box 6'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "social_security_wages": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total wages subject to Social Security tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Social security wages' or 'Box 3'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "wages_tips_other_comp": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total taxable wages, tips, and other compensation paid to the employee for the tax year. This is the primary income amount reported for federal tax purposes, often labeled as 'Wages, tips, other comp.' or 'Box 1'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "dependent_care_benefits": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total amount of dependent care benefits provided to the employee, if any. May be labeled as 'Dependent care benefits' or 'Box 10'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "medicare_wages_and_tips": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total wages and tips subject to Medicare tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Medicare wages and tips' or 'Box 5'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "employer_state_id_number": {
            "type": ["string", "null"],
            "description": "The employer's state identification number as reported on the wage and tax statement. This is used for state tax reporting and may be labeled as 'Employer's state ID no.' or similar.",
        },
        "federal_income_tax_withheld": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total amount of federal income tax withheld from the employee's pay for the tax year. This is the sum reported to the federal tax authority, often labeled as 'Federal income tax withheld' or 'Box 2'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "social_security_tax_withheld": {
            "type": "object",
            "required": ["amount", "iso_4217_currency_code"],
            "properties": {
                "amount": {"type": ["number", "null"]},
                "iso_4217_currency_code": {"type": ["string", "null"]},
            },
            "description": "The total amount of Social Security tax withheld from the employee's pay for the tax year. Often labeled as 'Social security tax withheld' or 'Box 4'.",
            "extend:type": "currency",
            "additionalProperties": False,
        },
        "employer_identification_number": {
            "type": ["string", "null"],
            "description": "The employer's federal Employer Identification Number (EIN), a nine-digit number often formatted as XX-XXXXXXX. Used for tax reporting purposes.",
        },
        "employee_social_security_number": {
            "type": ["string", "null"],
            "description": "The employee's Social Security Number (SSN) as reported on the wage and tax statement. This is a nine-digit identifier, often formatted as XXX-XX-XXXX. May be labeled as 'Employee's social security number' or similar.",
        },
    },
    "additionalProperties": False,
}


def process_w2_form(file_path: str) -> W2FormData:
    """
    Main entry point: parse and extract W2 form metadata
    @param file_path - Local file path to the W2 form PDF
    """
    print(f"[W2 Form] Processing: {file_path}")

    # Read file and convert to base64 data URL
    with open(file_path, "rb") as f:
        file_buffer = f.read()
    base64_str = __import__("base64").b64encode(file_buffer).decode("utf-8")
    mime_type = "application/pdf"
    data_url = f"data:{mime_type};base64,{base64_str}"

    # Step 1: Parse the document to markdown
    print("[Step 1/2] Parsing document structure and content...")
    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}")

    # Log parsed content for debugging
    parsed_content = "\n\n".join(
        [chunk.get("content", "") for chunk in parse_run.output.get("chunks", [])]
    )
    print(
        f"[Parsed] {len(parse_run.output.get('chunks', []))} chunks extracted"
    )
    print(f"[Sample] {parsed_content[:200]}...")

    # Step 2: Extract structured fields
    print("[Step 2/2] Extracting structured fields...")
    extract_run = client.extract_runs.create_and_poll(
        file={"url": data_url},
        config={
            "schema": extraction_schema,
            "base_processor": "extraction_performance",
        },
    )

    if extract_run.status != "PROCESSED":
        raise Exception(f"Extract failed with status: {extract_run.status}")

    extracted = extract_run.output.get("value", {})

    # Log results
    print("\n[Results] W2 Form Data:")
    print(f"  Employee Name: {extracted.get('employee_name')}")
    print(f"  Employer Name: {extracted.get('employer_name')}")
    print(f"  Tax Year: {extracted.get('tax_year')}")
    print(f"  State: {extracted.get('state')}")
    print(f"  Employee SSN: {extracted.get('employee_social_security_number')}")
    print(f"  Employer EIN: {extracted.get('employer_identification_number')}")
    print(f"  Wages, Tips, Other Comp: {extracted.get('wages_tips_other_comp')}")
    print(f"  Federal Income Tax Withheld: {extracted.get('federal_income_tax_withheld')}")
    print(f"  Social Security Wages: {extracted.get('social_security_wages')}")
    print(f"  Medicare Wages and Tips: {extracted.get('medicare_wages_and_tips')}")

    return extracted


if __name__ == "__main__":
    args = sys.argv[1:]
    if len(args) > 0:
        file_path = args[0]
        if not os.path.exists(file_path):
            print(f"File not found: {file_path}")
            sys.exit(1)
        try:
            result = process_w2_form(file_path)
            print("\n[Success] Extraction complete.")
            import json
            print(json.dumps(result, indent=2))
        except Exception as err:
            print(f"[Error] {str(err)}")
            sys.exit(1)
// This code uses Extend's REST API directly because Extend has no official Java SDK yet.
// It calls https://api.extend.ai endpoints using only Java's built-in java.net.http.HttpClient.

import java.io.IOException;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class UnderwritingPackageProcessor {

  private static final String API_BASE_URL = "https://api.extend.ai";
  private static final String API_KEY = System.getenv("EXTEND_API_KEY");
  private static final HttpClient httpClient = HttpClient.newHttpClient();

  /**
   * Main entry point: parse and extract underwriting package metadata
   * @param filePath - Local file path to the underwriting package PDF
   */
  public static Map<String, Object> processUnderwritingPackage(String filePath)
      throws IOException, InterruptedException {
    System.out.println("[Underwriting Package] Processing: " + filePath);

    // Read file and convert to data URL (base64)
    Path path = Paths.get(filePath);
    byte[] fileBytes = Files.readAllBytes(path);
    String base64 = Base64.getEncoder().encodeToString(fileBytes);
    String mimeType = "application/pdf";
    String dataUrl = "data:" + mimeType + ";base64," + base64;

    // Step 1: Parse the document to markdown
    System.out.println("[Step 1/2] Parsing document structure and content...");
    Map<String, Object> parseResult = callParseRun(dataUrl);
    String parseStatus = (String) parseResult.get("status");

    if (!"PROCESSED".equals(parseStatus)) {
      throw new RuntimeException("Parse failed with status: " + parseStatus);
    }

    System.out.println("[Parsed] Document parsed successfully");

    // Step 2: Extract structured fields
    System.out.println("[Step 2/2] Extracting structured fields...");
    Map<String, Object> extractResult = callExtractRun(dataUrl);
    String extractStatus = (String) extractResult.get("status");

    if (!"PROCESSED".equals(extractStatus)) {
      throw new RuntimeException("Extract failed with status: " + extractStatus);
    }

    @SuppressWarnings("unchecked")
    Map<String, Object> output = (Map<String, Object>) extractResult.get("output");
    @SuppressWarnings("unchecked")
    Map<String, Object> extracted = (Map<String, Object>) output.get("value");

    // Log results
    System.out.println("\n[Results] Underwriting Package Metadata:");
    System.out.println("  Lender: " + extracted.get("lender_name"));
    System.out.println("  Loan Number: " + extracted.get("loan_number"));
    System.out.println("  Loan Amount: " + extracted.get("loan_amount"));
    System.out.println("  Loan Type: " + extracted.get("loan_type"));
    System.out.println("  Assembly Date: " + extracted.get("assembly_date"));
    System.out.println("  Borrowers: " + extracted.get("borrowers"));
    System.out.println("  Property: " + extracted.get("subject_property_address"));
    System.out.println("  NMLS: " + extracted.get("nmls_number"));
    System.out.println("  Total Pages: " + extracted.get("total_pages"));
    System.out.println("  Total Documents: " + extracted.get("total_documents"));
    System.out.println("  Package Structure: " + extracted.get("package_structure"));

    return extracted;
  }

  private static Map<String, Object> callParseRun(String dataUrl)
      throws IOException, InterruptedException {
    String schema = buildUnderwritingPackageSchema();
    String requestBody =
        "{"
            + "\"file\":{\"url\":\""
            + escapeJson(dataUrl)
            + "\"},"
            + "\"config\":{"
            + "\"mode\":\"agentic_ocr\","
            + "\"outputType\":\"markdown\""
            + "}"
            + "}";

    HttpRequest request =
        HttpRequest.newBuilder()
            .uri(URI.create(API_BASE_URL + "/v1/parseRuns/createAndPoll"))
            .header("Authorization", "Bearer " + API_KEY)
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(requestBody))
            .build();

    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    return parseJsonResponse(response.body());
  }

  private static Map<String, Object> callExtractRun(String dataUrl)
      throws IOException, InterruptedException {
    String schema = buildUnderwritingPackageSchema();
    String requestBody =
        "{"
            + "\"file\":{\"url\":\""
            + escapeJson(dataUrl)
            + "\"},"
            + "\"config\":{"
            + "\"schema\":"
            + schema
            + ","
            + "\"baseProcessor\":\"extraction_performance\""
            + "}"
            + "}";

    HttpRequest request =
        HttpRequest.newBuilder()
            .uri(URI.create(API_BASE_URL + "/v1/extractRuns/createAndPoll"))
            .header("Authorization", "Bearer " + API_KEY)
            .header("Content-Type", "application/json")
            .POST(HttpRequest.BodyPublishers.ofString(requestBody))
            .build();

    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
    return parseJsonResponse(response.body());
  }

  private static String buildUnderwritingPackageSchema() {
    return "{"
        + "\"type\":\"object\","
        + "\"properties\":{"
        + "\"lender_name\":{\"type\":[\"string\",\"null\"],\"description\":\"Name of the lending institution\"},"
        + "\"lender_address\":{\"type\":[\"string\",\"null\"],\"description\":\"Complete mailing address of the lender\"},"
        + "\"nmls_number\":{\"type\":[\"string\",\"null\"],\"description\":\"NMLS identifier for the lender\"},"
        + "\"loan_number\":{\"type\":[\"string\",\"null\"],\"description\":\"Unique loan identification number\"},"
        + "\"assembly_date\":{\"type\":[\"string\",\"null\"],\"description\":\"Date the underwriting package was assembled in YYYY-MM-DD format\"},"
        + "\"borrowers\":{\"type\":[\"string\",\"null\"],\"description\":\"Names of primary borrower and co-borrowers\"},"
        + "\"subject_property_address\":{\"type\":[\"string\",\"null\"],\"description\":\"Physical street address of the subject property\"},"
        + "\"loan_type\":{\"type\":[\"string\",\"null\"],\"description\":\"Type and term of loan\"},"
        + "\"loan_amount\":{\"type\":[\"string\",\"null\"],\"description\":\"Principal loan amount in USD\"},"
        + "\"package_structure\":{\"type\":[\"string\",\"null\"],\"description\":\"Summary of package composition\"},"
        + "\"total_pages\":{\"type\":[\"string\",\"null\"],\"description\":\"Total number of pages in the underwriting package\"},"
        + "\"total_documents\":{\"type\":[\"string\",\"null\"],\"description\":\"Total number of distinct documents included\"}"
        + "}"
        + "}";
  }

  private static Map<String, Object> parseJsonResponse(String jsonString) {
    Map<String, Object> result = new HashMap<>();
    // Simple JSON parsing for response structure
    if (jsonString.contains("\"status\":\"PROCESSED\"")) {
      result.put("status", "PROCESSED");
    } else if (jsonString.contains("\"status\":\"FAILED\"")) {
      result.put("status", "FAILED");
    } else {
      result.put("status", "UNKNOWN");
    }

    // Extract output object
    int outputStart = jsonString.indexOf("\"output\":");
    if (outputStart != -1) {
      int braceStart = jsonString.indexOf("{", outputStart);
      int braceCount = 0;
      int braceEnd = braceStart;
      for (int i = braceStart; i < jsonString.length(); i++) {
        if (jsonString.charAt(i) == '{') braceCount++;
        if (jsonString.charAt(i) == '}') braceCount--;
        if (braceCount == 0) {
          braceEnd = i;
          break;
        }
      }
      String outputJson = jsonString.substring(braceStart, braceEnd + 1);
      result.put("output", parseNestedJson(outputJson));
    }

    return result;
  }

  private static Map<String, Object> parseNestedJson(String jsonString) {
    Map<String, Object> map = new HashMap<>();
    // Extract value field
    int valueStart = jsonString.indexOf("\"value\":");
    if (valueStart != -1) {
      int colonPos = jsonString.indexOf(":", valueStart);
      int braceStart = jsonString.indexOf("{", colonPos);
      if (braceStart != -1) {
        int braceCount = 0;
        int braceEnd = braceStart;
        for (int i = braceStart; i < jsonString.length(); i++) {
          if (jsonString.charAt(i) == '{') braceCount++;
          if (jsonString.charAt(i) == '}') braceCount--;
          if (braceCount == 0) {
            braceEnd = i;
            break;
          }
        }
        String valueJson = jsonString.substring(braceStart, braceEnd + 1);
        map.put("value", extractFieldsFromJson(valueJson));
      }
    }
    return map;
  }

  private static Map<String, Object> extractFieldsFromJson(String jsonString) {
    Map<String, Object> fields = new HashMap<>();
    String[] fieldNames = {
      "lender_name",
      "lender_address",
      "nmls_number",
      "loan_number",
      "assembly_date",
      "borrowers",
      "subject_property_address",
      "loan_type",
      "loan_amount",
      "package_structure",
      "total_pages",
      "total_documents"
    };

    for (String fieldName : fieldNames) {
      String value = extractStringField(jsonString, fieldName);
      fields.put(fieldName, value);
    }

    return fields;
  }

  private static String extractStringField(String jsonString, String fieldName) {
    String searchKey = "\"" + fieldName + "\":";
    int startIdx = jsonString.indexOf(searchKey);
    if (startIdx == -1) return null;

    int valueStart = startIdx + searchKey.length();
    while (valueStart < jsonString.length()
        && (jsonString.charAt(valueStart) == ' ' || jsonString.charAt(valueStart) == '\t')) {
      valueStart++;
    }

    if (valueStart >= jsonString.length()) return null;

    if (jsonString.charAt(valueStart) == '"') {
      int valueEnd = valueStart + 1;
      while (valueEnd < jsonString.length() && jsonString.charAt(valueEnd) != '"') {
        if (jsonString.charAt(valueEnd) == '\\') valueEnd++;
        valueEnd++;
      }
      if (valueEnd < jsonString.length()) {
        return jsonString.substring(valueStart + 1, valueEnd);
      }
    } else if (jsonString.startsWith("null", valueStart)) {
      return null;
    }

    return null;
  }

  private static String escapeJson(String input) {
    return input.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n");
  }

  public static void main(String[] args) {
    if (args.length == 0) {
      System.err.println("Usage: java UnderwritingPackageProcessor <file_path>");
      System.exit(1);
    }

    String filePath = args[0];
    Path path = Paths.get(filePath);
    if (!Files.exists(path)) {
      System.err.println("File not found: " + filePath);
      System.exit(1);
    }

    try {
      Map<String, Object> result = processUnderwritingPackage(filePath);
      System.out.println("\n[Success] Extraction complete.");
      System.out.println(formatJson(result));
    } catch (Exception e) {
      System.err.println("[Error] " + e.getMessage());
      e.printStackTrace();
      System.exit(1);
    }
  }

  private static String formatJson(Map<String, Object> map) {
    StringBuilder sb = new StringBuilder("{\n");
    map.forEach(
        (key, value) -> {
          sb.append("  \"").append(key).append("\": ");
          if (value == null) {
            sb.append("null");
          } else if (value instanceof String) {
            sb.append("\"").append(value).append("\"");
          } else {
            sb.append(value);
          }
          sb.append(",\n");
        });
    if (sb.length() > 2) {
      sb.setLength(sb.length() - 2);
    }
    sb.append("\n}");
    return sb.toString();
  }
}
// This code uses the Extend REST API directly because Extend has no official Go SDK yet.
// It calls https://api.extend.ai endpoints with Bearer token authentication.

package main

import (
	"bytes"
	"encoding/base64"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"os"
	"path/filepath"
	"time"
)

const extendAPIBase = "https://api.extend.ai"

// Box12Code represents a single code-value pair in Box 12
type Box12Code struct {
	Code        *string  `json:"code"`
	Amount      *float64 `json:"amount"`
	Description *string  `json:"description"`
}

// CurrencyAmount represents a monetary value with ISO 4217 currency code
type CurrencyAmount struct {
	Amount             *float64 `json:"amount"`
	ISO4217CurrencyCode *string `json:"iso_4217_currency_code"`
}

// W2Data represents the extracted W-2 wage and tax statement data
type W2Data struct {
	State                        *string           `json:"state"`
	TaxYear                      *string           `json:"tax_year"`
	Box12Codes                   []Box12Code       `json:"box_12_codes"`
	EmployeeName                 *string           `json:"employee_name"`
	EmployerName                 *string           `json:"employer_name"`
	LocalityName                 *string           `json:"locality_name"`
	AllocatedTips                *CurrencyAmount   `json:"allocated_tips"`
	ControlNumber                *string           `json:"control_number"`
	RetirementPlan               *bool             `json:"retirement_plan"`
	EmployeeAddress              *string           `json:"employee_address"`
	EmployerAddress              *string           `json:"employer_address"`
	LocalIncomeTax               *CurrencyAmount   `json:"local_income_tax"`
	StateIncomeTax               *CurrencyAmount   `json:"state_income_tax"`
	OtherInformation             *string           `json:"other_information"`
	NonqualifiedPlans            *CurrencyAmount   `json:"nonqualified_plans"`
	StatutoryEmployee            *bool             `json:"statutory_employee"`
	LocalWagesTipsEtc            *CurrencyAmount   `json:"local_wages_tips_etc"`
	SocialSecurityTips           *CurrencyAmount   `json:"social_security_tips"`
	StateWagesTipsEtc            *CurrencyAmount   `json:"state_wages_tips_etc"`
	ThirdPartySickPay            *bool             `json:"third_party_sick_pay"`
	MedicareTaxWithheld          *CurrencyAmount   `json:"medicare_tax_withheld"`
	SocialSecurityWages          *CurrencyAmount   `json:"social_security_wages"`
	WagesTipsOtherComp           *CurrencyAmount   `json:"wages_tips_other_comp"`
	DependentCareBenefits        *CurrencyAmount   `json:"dependent_care_benefits"`
	MedicareWagesAndTips         *CurrencyAmount   `json:"medicare_wages_and_tips"`
	EmployerStateIDNumber        *string           `json:"employer_state_id_number"`
	FederalIncomeTaxWithheld     *CurrencyAmount   `json:"federal_income_tax_withheld"`
	SocialSecurityTaxWithheld    *CurrencyAmount   `json:"social_security_tax_withheld"`
	EmployerIdentificationNumber *string           `json:"employer_identification_number"`
	EmployeeSocialSecurityNumber *string           `json:"employee_social_security_number"`
}

// ParseRunResponse represents the response from a parse run
type ParseRunResponse struct {
	Status string `json:"status"`
	Output struct {
		Chunks []struct {
			Content string `json:"content"`
		} `json:"chunks"`
	} `json:"output"`
}

// ExtractRunResponse represents the response from an extract run
type ExtractRunResponse struct {
	Status string `json:"status"`
	Output struct {
		Value W2Data `json:"value"`
	} `json:"output"`
}

// RunRequest represents a request to create a run
type RunRequest struct {
	File   FileInput  `json:"file"`
	Config ConfigInput `json:"config"`
}

// FileInput represents file input for a run
type FileInput struct {
	URL string `json:"url"`
}

// ConfigInput represents configuration for a run
type ConfigInput struct {
	Mode           string          `json:"mode,omitempty"`
	OutputType     string          `json:"outputType,omitempty"`
	Schema         json.RawMessage `json:"schema,omitempty"`
	BaseProcessor  string          `json:"baseProcessor,omitempty"`
}

// RunStatusResponse represents the status response from polling a run
type RunStatusResponse struct {
	Status string          `json:"status"`
	Output json.RawMessage `json:"output"`
}

func makeRequest(method, endpoint string, body interface{}, apiKey string) ([]byte, error) {
	url := extendAPIBase + endpoint
	var reqBody io.Reader
	if body != nil {
		jsonBody, err := json.Marshal(body)
		if err != nil {
			return nil, err
		}
		reqBody = bytes.NewReader(jsonBody)
	}

	req, err := http.NewRequest(method, url, reqBody)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", "Bearer "+apiKey)
	req.Header.Set("Content-Type", "application/json")

	client := &http.Client{}
	resp, err := client.Do(req)
	if err != nil {
		return nil, err
	}
	defer resp.Body.Close()

	respBody, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	if resp.StatusCode < 200 || resp.StatusCode >= 300 {
		return nil, fmt.Errorf("API error: status %d, body: %s", resp.StatusCode, string(respBody))
	}

	return respBody, nil
}

func pollRun(runID string, apiKey string, endpoint string) ([]byte, error) {
	maxAttempts := 120
	for attempt := 0; attempt < maxAttempts; attempt++ {
		respBody, err := makeRequest("GET", endpoint+"/"+runID, nil, apiKey)
		if err != nil {
			return nil, err
		}

		var statusResp RunStatusResponse
		if err := json.Unmarshal(respBody, &statusResp); err != nil {
			return nil, err
		}

		if statusResp.Status == "PROCESSED" {
			return statusResp.Output, nil
		}

		if statusResp.Status == "FAILED" || statusResp.Status == "ERROR" {
			return nil, fmt.Errorf("run failed with status: %s", statusResp.Status)
		}

		time.Sleep(1 * time.Second)
	}

	return nil, fmt.Errorf("run polling timeout")
}

// ProcessW2Document processes a W-2 wage and tax statement document
func ProcessW2Document(filePath string) (*W2Data, error) {
	apiKey := os.Getenv("EXTEND_API_KEY")
	if apiKey == "" {
		return nil, fmt.Errorf("EXTEND_API_KEY environment variable not set")
	}

	fmt.Printf("[W2 Document] Processing: %s\n", filePath)

	// Read file and convert to data URL (base64)
	fileBuffer, err := os.ReadFile(filePath)
	if err != nil {
		return nil, err
	}

	base64Str := base64.StdEncoding.EncodeToString(fileBuffer)
	mimeType := "application/pdf"
	dataURL := fmt.Sprintf("data:%s;base64,%s", mimeType, base64Str)

	// Step 1: Parse the document to markdown
	fmt.Println("[Step 1/2] Parsing document structure and content...")
	parseReq := RunRequest{
		File: FileInput{URL: dataURL},
		Config: ConfigInput{
			Mode:       "agentic_ocr",
			OutputType: "markdown",
		},
	}

	parseRespBody, err := makeRequest("POST", "/parse_runs", parseReq, apiKey)
	if err != nil {
		return nil, err
	}

	var parseResp struct {
		ID string `json:"id"`
	}
	if err := json.Unmarshal(parseRespBody, &parseResp); err != nil {
		return nil, err
	}

	parseOutputBody, err := pollRun(parseResp.ID, apiKey, "/parse_runs")
	if err != nil {
		return nil, err
	}

	var parseOutput ParseRunResponse
	if err := json.Unmarshal(parseOutputBody, &parseOutput); err != nil {
		return nil, err
	}

	if parseOutput.Status != "PROCESSED" {
		return nil, fmt.Errorf("parse failed with status: %s", parseOutput.Status)
	}

	parsedContent := ""
	for _, chunk := range parseOutput.Output.Chunks {
		parsedContent += chunk.Content + "\n\n"
	}
	fmt.Printf("[Parsed] %d chunks extracted\n", len(parseOutput.Output.Chunks))
	if len(parsedContent) > 200 {
		fmt.Printf("[Sample] %s...\n", parsedContent[:200])
	}

	// Step 2: Extract structured fields
	fmt.Println("[Step 2/2] Extracting structured fields...")

	// Build the schema as JSON
	schemaMap := map[string]interface{}{
		"type": "object",
		"properties": map[string]interface{}{
			"state":                           map[string]interface{}{"type": []string{"string", "null"}},
			"tax_year":                        map[string]interface{}{"type": []string{"string", "null"}},
			"box_12_codes":                    map[string]interface{}{"type": "array"},
			"employee_name":                   map[string]interface{}{"type": []string{"string", "null"}},
			"employer_name":                   map[string]interface{}{"type": []string{"string", "null"}},
			"locality_name":                   map[string]interface{}{"type": []string{"string", "null"}},
			"allocated_tips":                  map[string]interface{}{"extend:type": "currency"},
			"control_number":                  map[string]interface{}{"type": []string{"string", "null"}},
			"retirement_plan":                 map[string]interface{}{"type": []string{"boolean", "null"}},
			"employee_address":                map[string]interface{}{"type": []string{"string", "null"}},
			"employer_address":                map[string]interface{}{"type": []string{"string", "null"}},
			"local_income_tax":                map[string]interface{}{"extend:type": "currency"},
			"state_income_tax":                map[string]interface{}{"extend:type": "currency"},
			"other_information":               map[string]interface{}{"type": []string{"string", "null"}},
			"nonqualified_plans":              map[string]interface{}{"extend:type": "currency"},
			"statutory_employee":              map[string]interface{}{"type": []string{"boolean", "null"}},
			"local_wages_tips_etc":            map[string]interface{}{"extend:type": "currency"},
			"social_security_tips":            map[string]interface{}{"extend:type": "currency"},
			"state_wages_tips_etc":            map[string]interface{}{"extend:type": "currency"},
			"third_party_sick_pay":            map[string]interface{}{"type": []string{"boolean", "null"}},
			"medicare_tax_withheld":           map[string]interface{}{"extend:type": "currency"},
			"social_security_wages":           map[string]interface{}{"extend:type": "currency"},
			"wages_tips_other_comp":           map[string]interface{}{"extend:type": "currency"},
			"dependent_care_benefits":         map[string]interface{}{"extend:type": "currency"},
			"medicare_wages_and_tips":         map[string]interface{}{"extend:type": "currency"},
			"employer_state_id_number":        map[string]interface{}{"type": []string{"string", "null"}},
			"federal_income_tax_withheld":     map[string]interface{}{"extend:type": "currency"},
			"social_security_tax_withheld":    map[string]interface{}{"extend:type": "currency"},
			"employer_identification_number":  map[string]interface{}{"type": []string{"string", "null"}},
			"employee_social_security_number": map[string]interface{}{"type": []string{"string", "null"}},
		},
	}

	schemaJSON, _ := json.Marshal(schemaMap)

	extractReq := RunRequest{
		File: FileInput{URL: dataURL},
		Config: ConfigInput{
			Schema:        schemaJSON,
			BaseProcessor: "extraction_performance",
		},
	}

	extractRespBody, err := makeRequest("POST", "/extract_runs", extractReq, apiKey)
	if err != nil {
		return nil, err
	}

	var extractResp struct {
		ID string `json:"id"`
	}
	if err := json.Unmarshal(extractRespBody, &extractResp); err != nil {
		return nil, err
	}

	extractOutputBody, err := pollRun(extractResp.ID, apiKey, "/extract_runs")
	if err != nil {
		return nil, err
	}

	var extractOutput ExtractRunResponse
	if err := json.Unmarshal(extractOutputBody, &extractOutput); err != nil {
		return nil, err
	}

	if extractOutput.Status != "PROCESSED" {
		return nil, fmt.Errorf("extract failed with status: %s", extractOutput.Status)
	}

	extracted := &extractOutput.Output.Value

	// Log results
	fmt.Println("\n[Results] W-2 Wage and Tax Statement Data:")
	fmt.Printf("  Employee: %v\n", extracted.EmployeeName)
	fmt.Printf("  Employer: %v\n", extracted.EmployerName)
	fmt.Printf("  Tax Year: %v\n", extracted.TaxYear)
	fmt.Printf("  State: %v\n", extracted.State)
	fmt.Printf("  SSN: %v\n", extracted.EmployeeSocialSecurityNumber)
	fmt.Printf("  EIN: %v\n", extracted.EmployerIdentificationNumber)
	if extracted.WagesTipsOtherComp != nil {
		fmt.Printf("  Wages, Tips, Other Comp: %v %v\n", extracted.WagesTipsOtherComp.Amount, extracted.WagesTipsOtherComp.ISO4217CurrencyCode)
	}
	if extracted.FederalIncomeTaxWithheld != nil {
		fmt.Printf("  Federal Income Tax Withheld: %v %v\n", extracted.FederalIncomeTaxWithheld.Amount, extracted.FederalIncomeTaxWithheld.ISO4217CurrencyCode)
	}
	if extracted.SocialSecurityWages != nil {
		fmt.Printf("  Social Security Wages: %v %v\n", extracted.SocialSecurityWages.Amount, extracted.SocialSecurityWages.ISO4217CurrencyCode)
	}
	if extracted.MedicareWagesAndTips != nil {
		fmt.Printf("  Medicare Wages and Tips: %v %v\n", extracted.MedicareWagesAndTips.Amount, extracted.MedicareWagesAndTips.ISO4217CurrencyCode)
	}

	return extracted, nil
}

func main() {
	if len(os.Args) < 2 {
		fmt.Println("Usage: go run solution.go <path-to-pdf>")
		os.Exit(1)
	}

	filePath := os.Args[1]
	if _, err := os.Stat(filePath); err != nil {
		fmt.Printf("File not found: %s\n", filePath)
		os.Exit(1)
	}

	result, err := ProcessW2Document(filePath)
	if err != nil {
		fmt.Printf("[Error] %v\n", err)
		os.Exit(1)
	}

	fmt.Println("\n[Success] Extraction complete.")
	resultJSON, _ := json.MarshalIndent(result, "", "  ")
	fmt.Println(string(resultJSON))
}
// Deploy the "Underwriting Package" 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/underwriting-package.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: underwriting-package).

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, "underwriting-package.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": "Underwriting Package Processing Pipeline",
  "steps": [
    {
      "name": "startTrigger1",
      "type": "TRIGGER",
      "next": [
        {
          "step": "parse1"
        }
      ]
    },
    {
      "name": "parse1",
      "type": "PARSE",
      "config": {
        "parseConfig": {
          "blockOptions": {
            "text": {
              "agentic": {
                "enabled": true
              },
              "signatureDetectionEnabled": true
            },
            "tables": {
              "agentic": {
                "enabled": true
              },
              "tableHeaderContinuationEnabled": true
            },
            "figures": {
              "enabled": true
            }
          },
          "chunkingStrategy": {
            "type": "page",
            "options": {}
          }
        }
      },
      "next": [
        {
          "step": "split2"
        }
      ]
    },
    {
      "name": "split2",
      "type": "SPLIT",
      "config": {
        "splitterConfig": {
          "splitClassifications": [
            {
              "id": "splitter_classification1",
              "type": "other",
              "description": "Use the `other` document type when the document can not clearly be classified into one of the described classifications."
            },
            {
              "id": "subdocument_type_45c",
              "type": "Loan Transmittal Cover Sheet",
              "description": "Cover page listing loan snapshot, borrower information, loan team, and package contents summary"
            },
            {
              "id": "subdocument_type_VxE",
              "type": "Uniform Underwriting and Transmittal Summary",
              "description": "Standardized form summarizing borrower income, mortgage information, qualifying ratios, and underwriter comments"
            },
            {
              "id": "subdocument_type_Cvy",
              "type": "Underwriting Approval Certificate",
              "description": "Official conditional approval document listing prior-to-document and prior-to-funding conditions with status"
            },
            {
              "id": "subdocument_type__MG",
              "type": "Automated Underwriting Findings",
              "description": "System-generated AUS findings report showing approve/eligible recommendation and risk assessment"
            },
            {
              "id": "subdocument_type_jHc",
              "type": "Uniform Residential Loan Application",
              "description": "Multi-page standard mortgage application with borrower employment, income, assets, liabilities, and property information"
            },
            {
              "id": "subdocument_type_4mW",
              "type": "Demographic Information Addendum",
              "description": "Government monitoring form capturing borrower race, ethnicity, and sex information"
            },
            {
              "id": "subdocument_type_zwe",
              "type": "Loan Estimate",
              "description": "Three page federal disclosure showing estimated loan terms, projected payments, and closing costs"
            },
            {
              "id": "subdocument_type_6cV",
              "type": "Closing Disclosure",
              "description": "Five page federal form showing final loan terms and itemized closing costs"
            },
            {
              "id": "subdocument_type_uC_",
              "type": "Intent to Proceed",
              "description": "Signed borrower acknowledgment of intent to proceed with loan application"
            },
            {
              "id": "subdocument_type_anp",
              "type": "Settlement Service Provider List",
              "description": "Written list of approved third party service providers"
            },
            {
              "id": "subdocument_type_R7E",
              "type": "ECOA Fair Lending Notice",
              "description": "Federal notice of equal credit opportunity rights and right to receive appraisal copy"
            },
            {
              "id": "subdocument_type_PcP",
              "type": "Homeownership Counseling Disclosure",
              "description": "List of HUD approved housing counseling organizations"
            },
            {
              "id": "subdocument_type_Qqj",
              "type": "Borrower Certification and Authorization",
              "description": "Borrower certification that application is accurate and authorization to verify information"
            },
            {
              "id": "subdocument_type_HgI",
              "type": "Tax Return Transcript Request",
              "description": "IRS form authorizing lender to obtain tax transcripts directly from IRS"
            },
            {
              "id": "subdocument_type_KmI",
              "type": "Residential Mortgage Credit Report",
              "description": "Tri-merge credit report showing credit history, scores, and tradelines from all three bureaus"
            },
            {
              "id": "subdocument_type_MDu",
              "type": "Credit Score Disclosure",
              "description": "Notice to home loan applicant disclosing credit scores used in underwriting decision"
            },
            {
              "id": "subdocument_type_Uog",
              "type": "Letter of Explanation",
              "description": "Borrower written explanation for credit inquiries or derogatory items"
            },
            {
              "id": "subdocument_type_aDh",
              "type": "Undisclosed Debt Monitoring Report",
              "description": "Soft pull credit refresh to identify any new debt incurred during loan process"
            },
            {
              "id": "subdocument_type_QSG",
              "type": "Earnings Statement / Pay Stub",
              "description": "Recent pay stub showing gross earnings, deductions, and year to date totals"
            },
            {
              "id": "subdocument_type_p8F",
              "type": "W-2 Wage and Tax Statement",
              "description": "Annual employer wage statement showing total compensation and withholdings"
            },
            {
              "id": "subdocument_type_hsN",
              "type": "Written Verification of Employment",
              "description": "Employer completed form verifying borrower employment, position, income, and start date"
            },
            {
              "id": "subdocument_type_6Wm",
              "type": "Verbal Verification of Employment",
              "description": "Lender log documenting phone verification of borrower employment status"
            },
            {
              "id": "subdocument_type_dMz",
              "type": "Tax Return Transcript",
              "description": "IRS transcript of filed tax return showing income, AGI, and withholdings"
            },
            {
              "id": "subdocument_type_6La",
              "type": "Income Calculation Worksheet",
              "description": "Underwriter worksheet documenting income calculation methodology and qualifying amounts"
            },
            {
              "id": "subdocument_type_aKJ",
              "type": "Bank Statement Checking",
              "description": "Monthly checking account statement showing transactions, deposits, and ending balance"
            },
            {
              "id": "subdocument_type_KRI",
              "type": "Bank Statement Savings",
              "description": "Monthly savings account statement showing deposits and ending balance"
            },
            {
              "id": "subdocument_type_6jD",
              "type": "Brokerage Statement",
              "description": "Investment account statement showing holdings, market value, and available assets"
            },
            {
              "id": "subdocument_type_KHi",
              "type": "Retirement Account Statement",
              "description": "401k or 403b statement showing account balance and vested amount"
            },
            {
              "id": "subdocument_type_K70",
              "type": "Gift Letter",
              "description": "Signed letter from donor documenting gift amount, relationship, and confirmation no repayment required"
            },
            {
              "id": "subdocument_type_h5y",
              "type": "Earnest Money Deposit Evidence",
              "description": "Documentation of earnest money deposit showing funds cleared from borrower account"
            },
            {
              "id": "subdocument_type_iPz",
              "type": "Uniform Residential Appraisal Report",
              "description": "Full appraisal report with property description, comparable sales, and appraised value"
            },
            {
              "id": "subdocument_type_yh5",
              "type": "UCDP Submission Summary Report",
              "description": "Appraisal portal submission confirmation showing document file ID and status"
            },
            {
              "id": "subdocument_type_Z-j",
              "type": "Appraisal Invoice",
              "description": "Invoice and delivery acknowledgment from appraisal management company"
            },
            {
              "id": "subdocument_type_-PC",
              "type": "Flood Hazard Determination",
              "description": "Life of loan flood zone certification showing flood zone classification"
            },
            {
              "id": "subdocument_type_VOq",
              "type": "Title Insurance Commitment",
              "description": "Commitment for title insurance with Schedule A property details and Schedule B exceptions"
            },
            {
              "id": "subdocument_type_On9",
              "type": "Closing Protection Letter",
              "description": "Letter extending title underwriter protection to lender for closing agent acts"
            },
            {
              "id": "subdocument_type_UEl",
              "type": "Wire and Disbursement Instructions",
              "description": "Escrow agent wire instructions for funding disbursement"
            },
            {
              "id": "subdocument_type_0_8",
              "type": "Homeowners Insurance Declaration Page",
              "description": "Insurance policy declarations showing coverage amounts, premium, and mortgagee clause"
            },
            {
              "id": "subdocument_type_dZ3",
              "type": "Flood Insurance Exemption Notice",
              "description": "Lender notice that flood insurance is not required based on flood zone determination"
            },
            {
              "id": "subdocument_type_PBZ",
              "type": "Residential Purchase and Sale Agreement",
              "description": "Executed contract between buyer and seller including purchase price, terms, and contingencies"
            },
            {
              "id": "subdocument_type_2br",
              "type": "Seller Disclosure Notice",
              "description": "Seller's written disclosure of known property condition issues"
            },
            {
              "id": "subdocument_type_MO6",
              "type": "Verification of Rent",
              "description": "Documentation of borrower's current housing payment history"
            },
            {
              "id": "subdocument_type_Dgl",
              "type": "Government Photo ID",
              "description": "Copies of borrower government issued photo identification per USA PATRIOT Act requirements"
            },
            {
              "id": "subdocument_type_w1k",
              "type": "Loan Officer Compensation Disclosure",
              "description": "Anti-steering and loan officer compensation disclosure form"
            }
          ]
        }
      },
      "next": [
        {
          "step": "extraction3",
          "classificationId": "splitter_classification1"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_45c"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_VxE"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_Cvy"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type__MG"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_jHc"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_4mW"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_zwe"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_6cV"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_uC_"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_anp"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_R7E"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_PcP"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_Qqj"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_HgI"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_KmI"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_MDu"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_Uog"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_aDh"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_QSG"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_p8F"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_hsN"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_6Wm"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_dMz"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_6La"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_aKJ"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_KRI"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_6jD"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_KHi"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_K70"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_h5y"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_iPz"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_yh5"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_Z-j"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_-PC"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_VOq"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_On9"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_UEl"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_0_8"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_dZ3"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_PBZ"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_2br"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_MO6"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_Dgl"
        },
        {
          "step": "extraction3",
          "classificationId": "subdocument_type_w1k"
        }
      ]
    },
    {
      "name": "extraction3",
      "type": "EXTRACT",
      "config": {
        "extractorConfig": {
          "schema": {
            "type": "object",
            "required": [
              "state",
              "tax_year",
              "box_12_codes",
              "employee_name",
              "employer_name",
              "locality_name",
              "allocated_tips",
              "control_number",
              "retirement_plan",
              "employee_address",
              "employer_address",
              "local_income_tax",
              "state_income_tax",
              "other_information",
              "nonqualified_plans",
              "statutory_employee",
              "local_wages_tips_etc",
              "social_security_tips",
              "state_wages_tips_etc",
              "third_party_sick_pay",
              "medicare_tax_withheld",
              "social_security_wages",
              "wages_tips_other_comp",
              "dependent_care_benefits",
              "medicare_wages_and_tips",
              "employer_state_id_number",
              "federal_income_tax_withheld",
              "social_security_tax_withheld",
              "employer_identification_number",
              "employee_social_security_number"
            ],
            "properties": {
              "state": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The state in which the employer is located or where state wages and taxes are reported. May be labeled as 'State' or appear with the employer's address."
              },
              "tax_year": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The calendar year for which this wage and tax statement applies. This is the reporting year for the income and withholdings shown. Commonly appears as part of the document title or heading."
              },
              "box_12_codes": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "code",
                    "amount",
                    "description"
                  ],
                  "properties": {
                    "code": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "The single-letter or letter-number code used in Box 12 to indicate the type of compensation, deferral, or benefit (e.g., D, E, AA, etc.)."
                    },
                    "amount": {
                      "type": [
                        "number",
                        "null"
                      ],
                      "description": "The monetary value or amount associated with this Box 12 code, if applicable."
                    },
                    "description": {
                      "type": [
                        "string",
                        "null"
                      ],
                      "description": "A brief description of what the code represents, if available. May be present in document footnotes or instructions."
                    }
                  },
                  "additionalProperties": false
                },
                "description": "An array of code-value pairs reported in Box 12. Each entry represents a specific code (such as D, E, etc.) and the corresponding amount or value. These codes report various types of compensation, deferrals, or benefits. The codes and their meanings may vary by year and employer."
              },
              "employee_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The full legal name of the employee as reported on the wage and tax statement. Typically includes first name, middle initial, and last name, and may include suffixes. Commonly found near the employee's address."
              },
              "employer_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The legal name of the employer or company issuing this wage and tax statement. This is the entity that paid the employee and is responsible for reporting wages and withholdings."
              },
              "locality_name": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The name of the locality (city, county, or other jurisdiction) for which local wages and taxes are reported. May be labeled as 'Locality name' or 'Box 20'."
              },
              "allocated_tips": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The amount of tips allocated to the employee by the employer, if applicable. May be labeled as 'Allocated tips' or 'Box 8'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "control_number": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "A unique control or reference number assigned to this wage and tax statement by the employer or payroll processor. Used for internal tracking and may appear as 'Control number' or similar."
              },
              "retirement_plan": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Indicates whether the employee was an active participant in an employer-sponsored retirement plan during the tax year. This is typically marked as a checkbox or indicator."
              },
              "employee_address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The mailing address of the employee as reported on the wage and tax statement. May include street address, unit/apartment, city, state, and ZIP code. Can span multiple lines in some documents."
              },
              "employer_address": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The mailing address of the employer as reported on the wage and tax statement. May include street address, suite or unit, city, state, and ZIP code. Can span multiple lines."
              },
              "local_income_tax": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of local income tax withheld from the employee's pay for the tax year. May be labeled as 'Local income tax' or 'Box 19'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "state_income_tax": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of state income tax withheld from the employee's pay for the tax year. May be labeled as 'State income tax' or 'Box 17'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "other_information": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "Any additional information or miscellaneous codes reported in Box 14 or similar sections. This may include state-specific codes, explanations, or other employer-provided notes."
              },
              "nonqualified_plans": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount distributed to the employee from nonqualified deferred compensation plans. May be labeled as 'Nonqualified plans' or 'Box 11'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "statutory_employee": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Indicates whether the employee is classified as a statutory employee for tax purposes. This is typically marked as a checkbox or indicator on the wage and tax statement."
              },
              "local_wages_tips_etc": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of wages, tips, and other compensation subject to local income tax for the tax year. May be labeled as 'Local wages, tips, etc.' or 'Box 18'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "social_security_tips": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total tips reported by the employee that are subject to Social Security tax. May be labeled as 'Social security tips' or 'Box 7'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "state_wages_tips_etc": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of wages, tips, and other compensation subject to state income tax for the tax year. May be labeled as 'State wages, tips, etc.' or 'Box 16'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "third_party_sick_pay": {
                "type": [
                  "boolean",
                  "null"
                ],
                "description": "Indicates whether the employee received third-party sick pay during the tax year. This is typically marked as a checkbox or indicator."
              },
              "medicare_tax_withheld": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of Medicare tax withheld from the employee's pay for the tax year. Often labeled as 'Medicare tax withheld' or 'Box 6'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "social_security_wages": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total wages subject to Social Security tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Social security wages' or 'Box 3'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "wages_tips_other_comp": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total taxable wages, tips, and other compensation paid to the employee for the tax year. This is the primary income amount reported for federal tax purposes, often labeled as 'Wages, tips, other comp.' or 'Box 1'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "dependent_care_benefits": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of dependent care benefits provided to the employee, if any. May be labeled as 'Dependent care benefits' or 'Box 10'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "medicare_wages_and_tips": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total wages and tips subject to Medicare tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Medicare wages and tips' or 'Box 5'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "employer_state_id_number": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The employer's state identification number as reported on the wage and tax statement. This is used for state tax reporting and may be labeled as 'Employer's state ID no.' or similar."
              },
              "federal_income_tax_withheld": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of federal income tax withheld from the employee's pay for the tax year. This is the sum reported to the federal tax authority, often labeled as 'Federal income tax withheld' or 'Box 2'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "social_security_tax_withheld": {
                "type": "object",
                "required": [
                  "amount",
                  "iso_4217_currency_code"
                ],
                "properties": {
                  "amount": {
                    "type": [
                      "number",
                      "null"
                    ]
                  },
                  "iso_4217_currency_code": {
                    "type": [
                      "string",
                      "null"
                    ]
                  }
                },
                "description": "The total amount of Social Security tax withheld from the employee's pay for the tax year. Often labeled as 'Social security tax withheld' or 'Box 4'.",
                "extend:type": "currency",
                "additionalProperties": false
              },
              "employer_identification_number": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The employer's federal Employer Identification Number (EIN), a nine-digit number often formatted as XX-XXXXXXX. Used for tax reporting purposes."
              },
              "employee_social_security_number": {
                "type": [
                  "string",
                  "null"
                ],
                "description": "The employee's Social Security Number (SSN) as reported on the wage and tax statement. This is a nine-digit identifier, often formatted as XXX-XX-XXXX. May be labeled as 'Employee's social security number' or similar."
              }
            },
            "additionalProperties": false
          },
          "baseProcessor": "extraction_performance",
          "advancedOptions": {
            "reviewAgent": {
              "enabled": false
            },
            "advancedMultimodalEnabled": false
          }
        }
      }
    }
  ]
};

async function main() {
  console.log(`Deploying "${WORKFLOW.name}"…`);

  if (state.workflowId) {
    console.log(`✓ workflow already provisioned (${state.workflowId}) — updating steps`);
    await api("POST", `/workflows/${state.workflowId}`, { steps: WORKFLOW.steps });
  } else {
    // Reuse an existing workflow with the same name if one exists (e.g. a
    // previous run's state file was lost) instead of creating a duplicate.
    try {
      const list = await api("GET", `/workflows?name=${encodeURIComponent(WORKFLOW.name)}`);
      const items = (list.data ?? list.items ?? []) as Array<{ name?: string; id?: string }>;
      const existing = items.find((x) => x.name === WORKFLOW.name);
      if (existing?.id) {
        state.workflowId = existing.id; saveState();
        console.log(`✓ workflow "${WORKFLOW.name}" found in your account (${existing.id}) — updating steps`);
        await api("POST", `/workflows/${existing.id}`, { steps: WORKFLOW.steps });
      }
    } catch { /* lookup is best-effort; fall through to create */ }

    if (!state.workflowId) {
      const created = await api("POST", "/workflows", WORKFLOW);
      const wfId = created.id ?? created.workflow?.id;
      if (!wfId) throw new Error("Could not read created workflow id from response");
      state.workflowId = wfId; saveState();
      console.log(`+ created workflow (${wfId})`);
    }
  }

  // Deploy the current draft as a new version so the workflow is runnable —
  // best-effort: some accounts/plans may not require this explicit step.
  await api("POST", `/workflows/${state.workflowId}/versions`, {}).catch(() => {});

  console.log("\nDone. Run documents through it with:");
  console.log(`  POST ${API}/workflow_runs  { workflow: { id: "${state.workflowId}" }, file: { url: "https://…" } }`);
  console.log("Or open the workflow in the Extend dashboard to review and deploy it.");
}

main().catch((e) => { console.error(e.message ?? e); process.exit(1); });
import os
import json
import sys
from pathlib import Path
from typing import Any, Optional

from extend_ai import Extend

API_KEY = os.environ.get("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 / "underwriting-package.json"

state: dict[str, Optional[str]] = {}
if STATE_FILE.exists():
    state = json.loads(STATE_FILE.read_text())


def save_state() -> None:
    STATE_DIR.mkdir(parents=True, exist_ok=True)
    STATE_FILE.write_text(json.dumps(state, indent=2))


WORKFLOW = {
    "name": "Underwriting Package Processing Pipeline",
    "steps": [
        {
            "name": "startTrigger1",
            "type": "TRIGGER",
            "next": [{"step": "parse1"}],
        },
        {
            "name": "parse1",
            "type": "PARSE",
            "config": {
                "parseConfig": {
                    "blockOptions": {
                        "text": {
                            "agentic": {"enabled": True},
                            "signatureDetectionEnabled": True,
                        },
                        "tables": {
                            "agentic": {"enabled": True},
                            "tableHeaderContinuationEnabled": True,
                        },
                        "figures": {"enabled": True},
                    },
                    "chunkingStrategy": {"type": "page", "options": {}},
                }
            },
            "next": [{"step": "split2"}],
        },
        {
            "name": "split2",
            "type": "SPLIT",
            "config": {
                "splitterConfig": {
                    "splitClassifications": [
                        {
                            "id": "splitter_classification1",
                            "type": "other",
                            "description": "Use the `other` document type when the document can not clearly be classified into one of the described classifications.",
                        },
                        {
                            "id": "subdocument_type_45c",
                            "type": "Loan Transmittal Cover Sheet",
                            "description": "Cover page listing loan snapshot, borrower information, loan team, and package contents summary",
                        },
                        {
                            "id": "subdocument_type_VxE",
                            "type": "Uniform Underwriting and Transmittal Summary",
                            "description": "Standardized form summarizing borrower income, mortgage information, qualifying ratios, and underwriter comments",
                        },
                        {
                            "id": "subdocument_type_Cvy",
                            "type": "Underwriting Approval Certificate",
                            "description": "Official conditional approval document listing prior-to-document and prior-to-funding conditions with status",
                        },
                        {
                            "id": "subdocument_type__MG",
                            "type": "Automated Underwriting Findings",
                            "description": "System-generated AUS findings report showing approve/eligible recommendation and risk assessment",
                        },
                        {
                            "id": "subdocument_type_jHc",
                            "type": "Uniform Residential Loan Application",
                            "description": "Multi-page standard mortgage application with borrower employment, income, assets, liabilities, and property information",
                        },
                        {
                            "id": "subdocument_type_4mW",
                            "type": "Demographic Information Addendum",
                            "description": "Government monitoring form capturing borrower race, ethnicity, and sex information",
                        },
                        {
                            "id": "subdocument_type_zwe",
                            "type": "Loan Estimate",
                            "description": "Three page federal disclosure showing estimated loan terms, projected payments, and closing costs",
                        },
                        {
                            "id": "subdocument_type_6cV",
                            "type": "Closing Disclosure",
                            "description": "Five page federal form showing final loan terms and itemized closing costs",
                        },
                        {
                            "id": "subdocument_type_uC_",
                            "type": "Intent to Proceed",
                            "description": "Signed borrower acknowledgment of intent to proceed with loan application",
                        },
                        {
                            "id": "subdocument_type_anp",
                            "type": "Settlement Service Provider List",
                            "description": "Written list of approved third party service providers",
                        },
                        {
                            "id": "subdocument_type_R7E",
                            "type": "ECOA Fair Lending Notice",
                            "description": "Federal notice of equal credit opportunity rights and right to receive appraisal copy",
                        },
                        {
                            "id": "subdocument_type_PcP",
                            "type": "Homeownership Counseling Disclosure",
                            "description": "List of HUD approved housing counseling organizations",
                        },
                        {
                            "id": "subdocument_type_Qqj",
                            "type": "Borrower Certification and Authorization",
                            "description": "Borrower certification that application is accurate and authorization to verify information",
                        },
                        {
                            "id": "subdocument_type_HgI",
                            "type": "Tax Return Transcript Request",
                            "description": "IRS form authorizing lender to obtain tax transcripts directly from IRS",
                        },
                        {
                            "id": "subdocument_type_KmI",
                            "type": "Residential Mortgage Credit Report",
                            "description": "Tri-merge credit report showing credit history, scores, and tradelines from all three bureaus",
                        },
                        {
                            "id": "subdocument_type_MDu",
                            "type": "Credit Score Disclosure",
                            "description": "Notice to home loan applicant disclosing credit scores used in underwriting decision",
                        },
                        {
                            "id": "subdocument_type_Uog",
                            "type": "Letter of Explanation",
                            "description": "Borrower written explanation for credit inquiries or derogatory items",
                        },
                        {
                            "id": "subdocument_type_aDh",
                            "type": "Undisclosed Debt Monitoring Report",
                            "description": "Soft pull credit refresh to identify any new debt incurred during loan process",
                        },
                        {
                            "id": "subdocument_type_QSG",
                            "type": "Earnings Statement / Pay Stub",
                            "description": "Recent pay stub showing gross earnings, deductions, and year to date totals",
                        },
                        {
                            "id": "subdocument_type_p8F",
                            "type": "W-2 Wage and Tax Statement",
                            "description": "Annual employer wage statement showing total compensation and withholdings",
                        },
                        {
                            "id": "subdocument_type_hsN",
                            "type": "Written Verification of Employment",
                            "description": "Employer completed form verifying borrower employment, position, income, and start date",
                        },
                        {
                            "id": "subdocument_type_6Wm",
                            "type": "Verbal Verification of Employment",
                            "description": "Lender log documenting phone verification of borrower employment status",
                        },
                        {
                            "id": "subdocument_type_dMz",
                            "type": "Tax Return Transcript",
                            "description": "IRS transcript of filed tax return showing income, AGI, and withholdings",
                        },
                        {
                            "id": "subdocument_type_6La",
                            "type": "Income Calculation Worksheet",
                            "description": "Underwriter worksheet documenting income calculation methodology and qualifying amounts",
                        },
                        {
                            "id": "subdocument_type_aKJ",
                            "type": "Bank Statement Checking",
                            "description": "Monthly checking account statement showing transactions, deposits, and ending balance",
                        },
                        {
                            "id": "subdocument_type_KRI",
                            "type": "Bank Statement Savings",
                            "description": "Monthly savings account statement showing deposits and ending balance",
                        },
                        {
                            "id": "subdocument_type_6jD",
                            "type": "Brokerage Statement",
                            "description": "Investment account statement showing holdings, market value, and available assets",
                        },
                        {
                            "id": "subdocument_type_KHi",
                            "type": "Retirement Account Statement",
                            "description": "401k or 403b statement showing account balance and vested amount",
                        },
                        {
                            "id": "subdocument_type_K70",
                            "type": "Gift Letter",
                            "description": "Signed letter from donor documenting gift amount, relationship, and confirmation no repayment required",
                        },
                        {
                            "id": "subdocument_type_h5y",
                            "type": "Earnest Money Deposit Evidence",
                            "description": "Documentation of earnest money deposit showing funds cleared from borrower account",
                        },
                        {
                            "id": "subdocument_type_iPz",
                            "type": "Uniform Residential Appraisal Report",
                            "description": "Full appraisal report with property description, comparable sales, and appraised value",
                        },
                        {
                            "id": "subdocument_type_yh5",
                            "type": "UCDP Submission Summary Report",
                            "description": "Appraisal portal submission confirmation showing document file ID and status",
                        },
                        {
                            "id": "subdocument_type_Z-j",
                            "type": "Appraisal Invoice",
                            "description": "Invoice and delivery acknowledgment from appraisal management company",
                        },
                        {
                            "id": "subdocument_type_-PC",
                            "type": "Flood Hazard Determination",
                            "description": "Life of loan flood zone certification showing flood zone classification",
                        },
                        {
                            "id": "subdocument_type_VOq",
                            "type": "Title Insurance Commitment",
                            "description": "Commitment for title insurance with Schedule A property details and Schedule B exceptions",
                        },
                        {
                            "id": "subdocument_type_On9",
                            "type": "Closing Protection Letter",
                            "description": "Letter extending title underwriter protection to lender for closing agent acts",
                        },
                        {
                            "id": "subdocument_type_UEl",
                            "type": "Wire and Disbursement Instructions",
                            "description": "Escrow agent wire instructions for funding disbursement",
                        },
                        {
                            "id": "subdocument_type_0_8",
                            "type": "Homeowners Insurance Declaration Page",
                            "description": "Insurance policy declarations showing coverage amounts, premium, and mortgagee clause",
                        },
                        {
                            "id": "subdocument_type_dZ3",
                            "type": "Flood Insurance Exemption Notice",
                            "description": "Lender notice that flood insurance is not required based on flood zone determination",
                        },
                        {
                            "id": "subdocument_type_PBZ",
                            "type": "Residential Purchase and Sale Agreement",
                            "description": "Executed contract between buyer and seller including purchase price, terms, and contingencies",
                        },
                        {
                            "id": "subdocument_type_2br",
                            "type": "Seller Disclosure Notice",
                            "description": "Seller's written disclosure of known property condition issues",
                        },
                        {
                            "id": "subdocument_type_MO6",
                            "type": "Verification of Rent",
                            "description": "Documentation of borrower's current housing payment history",
                        },
                        {
                            "id": "subdocument_type_Dgl",
                            "type": "Government Photo ID",
                            "description": "Copies of borrower government issued photo identification per USA PATRIOT Act requirements",
                        },
                        {
                            "id": "subdocument_type_w1k",
                            "type": "Loan Officer Compensation Disclosure",
                            "description": "Anti-steering and loan officer compensation disclosure form",
                        },
                    ]
                }
            },
            "next": [
                {"step": "extraction3", "classificationId": "splitter_classification1"},
                {"step": "extraction3", "classificationId": "subdocument_type_45c"},
                {"step": "extraction3", "classificationId": "subdocument_type_VxE"},
                {"step": "extraction3", "classificationId": "subdocument_type_Cvy"},
                {"step": "extraction3", "classificationId": "subdocument_type__MG"},
                {"step": "extraction3", "classificationId": "subdocument_type_jHc"},
                {"step": "extraction3", "classificationId": "subdocument_type_4mW"},
                {"step": "extraction3", "classificationId": "subdocument_type_zwe"},
                {"step": "extraction3", "classificationId": "subdocument_type_6cV"},
                {"step": "extraction3", "classificationId": "subdocument_type_uC_"},
                {"step": "extraction3", "classificationId": "subdocument_type_anp"},
                {"step": "extraction3", "classificationId": "subdocument_type_R7E"},
                {"step": "extraction3", "classificationId": "subdocument_type_PcP"},
                {"step": "extraction3", "classificationId": "subdocument_type_Qqj"},
                {"step": "extraction3", "classificationId": "subdocument_type_HgI"},
                {"step": "extraction3", "classificationId": "subdocument_type_KmI"},
                {"step": "extraction3", "classificationId": "subdocument_type_MDu"},
                {"step": "extraction3", "classificationId": "subdocument_type_Uog"},
                {"step": "extraction3", "classificationId": "subdocument_type_aDh"},
                {"step": "extraction3", "classificationId": "subdocument_type_QSG"},
                {"step": "extraction3", "classificationId": "subdocument_type_p8F"},
                {"step": "extraction3", "classificationId": "subdocument_type_hsN"},
                {"step": "extraction3", "classificationId": "subdocument_type_6Wm"},
                {"step": "extraction3", "classificationId": "subdocument_type_dMz"},
                {"step": "extraction3", "classificationId": "subdocument_type_6La"},
                {"step": "extraction3", "classificationId": "subdocument_type_aKJ"},
                {"step": "extraction3", "classificationId": "subdocument_type_KRI"},
                {"step": "extraction3", "classificationId": "subdocument_type_6jD"},
                {"step": "extraction3", "classificationId": "subdocument_type_KHi"},
                {"step": "extraction3", "classificationId": "subdocument_type_K70"},
                {"step": "extraction3", "classificationId": "subdocument_type_h5y"},
                {"step": "extraction3", "classificationId": "subdocument_type_iPz"},
                {"step": "extraction3", "classificationId": "subdocument_type_yh5"},
                {"step": "extraction3", "classificationId": "subdocument_type_Z-j"},
                {"step": "extraction3", "classificationId": "subdocument_type_-PC"},
                {"step": "extraction3", "classificationId": "subdocument_type_VOq"},
                {"step": "extraction3", "classificationId": "subdocument_type_On9"},
                {"step": "extraction3", "classificationId": "subdocument_type_UEl"},
                {"step": "extraction3", "classificationId": "subdocument_type_0_8"},
                {"step": "extraction3", "classificationId": "subdocument_type_dZ3"},
                {"step": "extraction3", "classificationId": "subdocument_type_PBZ"},
                {"step": "extraction3", "classificationId": "subdocument_type_2br"},
                {"step": "extraction3", "classificationId": "subdocument_type_MO6"},
                {"step": "extraction3", "classificationId": "subdocument_type_Dgl"},
                {"step": "extraction3", "classificationId": "subdocument_type_w1k"},
            ],
        },
        {
            "name": "extraction3",
            "type": "EXTRACT",
            "config": {
                "extractorConfig": {
                    "schema": {
                        "type": "object",
                        "required": [
                            "state",
                            "tax_year",
                            "box_12_codes",
                            "employee_name",
                            "employer_name",
                            "locality_name",
                            "allocated_tips",
                            "control_number",
                            "retirement_plan",
                            "employee_address",
                            "employer_address",
                            "local_income_tax",
                            "state_income_tax",
                            "other_information",
                            "nonqualified_plans",
                            "statutory_employee",
                            "local_wages_tips_etc",
                            "social_security_tips",
                            "state_wages_tips_etc",
                            "third_party_sick_pay",
                            "medicare_tax_withheld",
                            "social_security_wages",
                            "wages_tips_other_comp",
                            "dependent_care_benefits",
                            "medicare_wages_and_tips",
                            "employer_state_id_number",
                            "federal_income_tax_withheld",
                            "social_security_tax_withheld",
                            "employer_identification_number",
                            "employee_social_security_number",
                        ],
                        "properties": {
                            "state": {
                                "type": ["string", "null"],
                                "description": "The state in which the employer is located or where state wages and taxes are reported. May be labeled as 'State' or appear with the employer's address.",
                            },
                            "tax_year": {
                                "type": ["string", "null"],
                                "description": "The calendar year for which this wage and tax statement applies. This is the reporting year for the income and withholdings shown. Commonly appears as part of the document title or heading.",
                            },
                            "box_12_codes": {
                                "type": "array",
                                "items": {
                                    "type": "object",
                                    "required": ["code", "amount", "description"],
                                    "properties": {
                                        "code": {
                                            "type": ["string", "null"],
                                            "description": "The single-letter or letter-number code used in Box 12 to indicate the type of compensation, deferral, or benefit (e.g., D, E, AA, etc.).",
                                        },
                                        "amount": {
                                            "type": ["number", "null"],
                                            "description": "The monetary value or amount associated with this Box 12 code, if applicable.",
                                        },
                                        "description": {
                                            "type": ["string", "null"],
                                            "description": "A brief description of what the code represents, if available. May be present in document footnotes or instructions.",
                                        },
                                    },
                                    "additionalProperties": False,
                                },
                                "description": "An array of code-value pairs reported in Box 12. Each entry represents a specific code (such as D, E, etc.) and the corresponding amount or value. These codes report various types of compensation, deferrals, or benefits. The codes and their meanings may vary by year and employer.",
                            },
                            "employee_name": {
                                "type": ["string", "null"],
                                "description": "The full legal name of the employee as reported on the wage and tax statement. Typically includes first name, middle initial, and last name, and may include suffixes. Commonly found near the employee's address.",
                            },
                            "employer_name": {
                                "type": ["string", "null"],
                                "description": "The legal name of the employer or company issuing this wage and tax statement. This is the entity that paid the employee and is responsible for reporting wages and withholdings.",
                            },
                            "locality_name": {
                                "type": ["string", "null"],
                                "description": "The name of the locality (city, county, or other jurisdiction) for which local wages and taxes are reported. May be labeled as 'Locality name' or 'Box 20'.",
                            },
                            "allocated_tips": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The amount of tips allocated to the employee by the employer, if applicable. May be labeled as 'Allocated tips' or 'Box 8'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "control_number": {
                                "type": ["string", "null"],
                                "description": "A unique control or reference number assigned to this wage and tax statement by the employer or payroll processor. Used for internal tracking and may appear as 'Control number' or similar.",
                            },
                            "retirement_plan": {
                                "type": ["boolean", "null"],
                                "description": "Indicates whether the employee was an active participant in an employer-sponsored retirement plan during the tax year. This is typically marked as a checkbox or indicator.",
                            },
                            "employee_address": {
                                "type": ["string", "null"],
                                "description": "The mailing address of the employee as reported on the wage and tax statement. May include street address, unit/apartment, city, state, and ZIP code. Can span multiple lines in some documents.",
                            },
                            "employer_address": {
                                "type": ["string", "null"],
                                "description": "The mailing address of the employer as reported on the wage and tax statement. May include street address, suite or unit, city, state, and ZIP code. Can span multiple lines.",
                            },
                            "local_income_tax": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total amount of local income tax withheld from the employee's pay for the tax year. May be labeled as 'Local income tax' or 'Box 19'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "state_income_tax": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total amount of state income tax withheld from the employee's pay for the tax year. May be labeled as 'State income tax' or 'Box 17'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "other_information": {
                                "type": ["string", "null"],
                                "description": "Any additional information or miscellaneous codes reported in Box 14 or similar sections. This may include state-specific codes, explanations, or other employer-provided notes.",
                            },
                            "nonqualified_plans": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total amount distributed to the employee from nonqualified deferred compensation plans. May be labeled as 'Nonqualified plans' or 'Box 11'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "statutory_employee": {
                                "type": ["boolean", "null"],
                                "description": "Indicates whether the employee is classified as a statutory employee for tax purposes. This is typically marked as a checkbox or indicator on the wage and tax statement.",
                            },
                            "local_wages_tips_etc": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total amount of wages, tips, and other compensation subject to local income tax for the tax year. May be labeled as 'Local wages, tips, etc.' or 'Box 18'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "social_security_tips": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total tips reported by the employee that are subject to Social Security tax. May be labeled as 'Social security tips' or 'Box 7'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "state_wages_tips_etc": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total amount of wages, tips, and other compensation subject to state income tax for the tax year. May be labeled as 'State wages, tips, etc.' or 'Box 16'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "third_party_sick_pay": {
                                "type": ["boolean", "null"],
                                "description": "Indicates whether the employee received third-party sick pay during the tax year. This is typically marked as a checkbox or indicator.",
                            },
                            "medicare_tax_withheld": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total amount of Medicare tax withheld from the employee's pay for the tax year. Often labeled as 'Medicare tax withheld' or 'Box 6'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "social_security_wages": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total wages subject to Social Security tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Social security wages' or 'Box 3'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "wages_tips_other_comp": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total taxable wages, tips, and other compensation paid to the employee for the tax year. This is the primary income amount reported for federal tax purposes, often labeled as 'Wages, tips, other comp.' or 'Box 1'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "dependent_care_benefits": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total amount of dependent care benefits provided to the employee, if any. May be labeled as 'Dependent care benefits' or 'Box 10'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "medicare_wages_and_tips": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total wages and tips subject to Medicare tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Medicare wages and tips' or 'Box 5'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "employer_state_id_number": {
                                "type": ["string", "null"],
                                "description": "The employer's state identification number as reported on the wage and tax statement. This is used for state tax reporting and may be labeled as 'Employer's state ID no.' or similar.",
                            },
                            "federal_income_tax_withheld": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total amount of federal income tax withheld from the employee's pay for the tax year. This is the sum reported to the federal tax authority, often labeled as 'Federal income tax withheld' or 'Box 2'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "social_security_tax_withheld": {
                                "type": "object",
                                "required": ["amount", "iso_4217_currency_code"],
                                "properties": {
                                    "amount": {"type": ["number", "null"]},
                                    "iso_4217_currency_code": {"type": ["string", "null"]},
                                },
                                "description": "The total amount of Social Security tax withheld from the employee's pay for the tax year. Often labeled as 'Social security tax withheld' or 'Box 4'.",
                                "extend:type": "currency",
                                "additionalProperties": False,
                            },
                            "employer_identification_number": {
                                "type": ["string", "null"],
                                "description": "The employer's federal Employer Identification Number (EIN), a nine-digit number often formatted as XX-XXXXXXX. Used for tax reporting purposes.",
                            },
                            "employee_social_security_number": {
                                "type": ["string", "null"],
                                "description": "The employee's Social Security Number (SSN) as reported on the wage and tax statement. This is a nine-digit identifier, often formatted as XXX-XX-XXXX. May be labeled as 'Employee's social security number' or similar.",
                            },
                        },
                        "additionalProperties": False,
                    },
                    "baseProcessor": "extraction_performance",
                    "advancedOptions": {
                        "reviewAgent": {"enabled": False},
                        "advancedMultimodalEnabled": False,
                    },
                }
            },
        },
    ],
}


def main() -> None:
    client = Extend(token=API_KEY)

    print(f'Deploying "{WORKFLOW["name"]}…')

    if state.get("workflowId"):
        workflow_id = state["workflowId"]
        print(f"✓ workflow already provisioned ({workflow_id}) — updating steps")
        client.workflows.update(workflow_id, steps=WORKFLOW["steps"])
    else:
        try:
            workflows_list = client.workflows.list(name=WORKFLOW["name"])
            items = workflows_list.data if hasattr(workflows_list, "data") else (
                workflows_list.items if hasattr(workflows_list, "items") else []
            )
            existing = next(
                (w for w in items if getattr(w, "name", None) == WORKFLOW["name"]),
                None,
            )
            if existing and getattr(existing, "id", None):
                state["workflowId"] = existing.id
                save_state()
                print(
                    f'✓ workflow "{WORKFLOW["name"]}" found in your account ({existing.id}) — updating steps'
                )
                client.workflows.update(existing.id, steps=WORKFLOW["steps"])
        except Exception:
            pass

        if not state.get("workflowId"):
            created = client.workflows.create(**WORKFLOW)
            workflow_id = getattr(created, "id", None) or getattr(
                getattr(created, "workflow", None), "id", None
            )
            if not workflow_id:
                raise RuntimeError("Could not read created workflow id from response")
            state["workflowId"] = workflow_id
            save_state()
            print(f"+ created workflow ({workflow_id})")

    try:
        client.workflows.create_version(state["workflowId"])
    except Exception:
        pass

    print("\nDone. Run documents through it with:")
    print(
        f'  POST https://api.extend.ai/workflow_runs  {{ "workflow": {{ "id": "{state["workflowId"]}" }}, "file": {{ "url": "https://…" }} }}'
    )
    print("Or open the workflow in the Extend dashboard to review and deploy it.")


if __name__ == "__main__":
    try:
        main()
    except Exception as e:
        print(str(e), file=sys.stderr)
        sys.exit(1)
// Extend REST API provisioning script for "Underwriting Package" template.
// Extend does NOT publish an official Java SDK — this code calls the REST API directly
// using only java.net.http.HttpClient (no third-party HTTP or JSON libraries).
//
// Usage:
//   export EXTEND_API_KEY=sk_...   (from https://dashboard.extend.ai → API Keys)
//   javac Provision.java && java Provision

import java.io.*;
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.*;

public class Provision {
  private static final String API = "https://api.extend.ai";
  private static final String VERSION = "2026-02-09";
  private static final String API_KEY = System.getenv("EXTEND_API_KEY");
  private static final Path STATE_DIR = Paths.get(System.getProperty("user.dir"), ".extend");
  private static final Path STATE_FILE = STATE_DIR.resolve("underwriting-package.json");

  static {
    if (API_KEY == null || API_KEY.isEmpty()) {
      System.err.println("Set EXTEND_API_KEY first.");
      System.exit(1);
    }
  }

  private static class State {
    String workflowId;
  }

  private static State state = new State();
  private static final HttpClient httpClient = HttpClient.newHttpClient();

  static {
    try {
      if (Files.exists(STATE_FILE)) {
        String content = Files.readString(STATE_FILE);
        state.workflowId = parseJsonField(content, "workflowId");
      }
    } catch (IOException e) {
      // State file doesn't exist yet; continue with empty state
    }
  }

  private static void saveState() throws IOException {
    Files.createDirectories(STATE_DIR);
    String json = "{\"workflowId\": \"" + (state.workflowId != null ? state.workflowId : "") + "\"}";
    Files.writeString(STATE_FILE, json);
  }

  private static String parseJsonField(String json, String fieldName) {
    String pattern = "\"" + fieldName + "\"\\s*:\\s*\"([^\"]*)\"";
    java.util.regex.Pattern p = java.util.regex.Pattern.compile(pattern);
    java.util.regex.Matcher m = p.matcher(json);
    return m.find() ? m.group(1) : null;
  }

  private static String apiCall(String method, String pathName, String body) throws Exception {
    HttpRequest.Builder builder = HttpRequest.newBuilder()
        .uri(URI.create(API + pathName))
        .method(method, body != null ? HttpRequest.BodyPublishers.ofString(body) : HttpRequest.BodyPublishers.noBody())
        .header("Authorization", "Bearer " + API_KEY)
        .header("x-extend-api-version", VERSION);

    if (body != null) {
      builder.header("Content-Type", "application/json");
    }

    HttpRequest request = builder.build();
    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

    if (response.statusCode() < 200 || response.statusCode() >= 300) {
      String errorMsg = response.body().length() > 300 ? response.body().substring(0, 300) : response.body();
      throw new Exception(method + " " + pathName + " failed (" + response.statusCode() + "): " + errorMsg);
    }

    return response.body();
  }

  private static String buildWorkflowJson() {
    StringBuilder sb = new StringBuilder();
    sb.append("{");
    sb.append("\"name\":\"Underwriting Package Processing Pipeline\",");
    sb.append("\"steps\":[");

    // startTrigger1
    sb.append("{\"name\":\"startTrigger1\",\"type\":\"TRIGGER\",\"next\":[{\"step\":\"parse1\"}]},");

    // parse1
    sb.append("{\"name\":\"parse1\",\"type\":\"PARSE\",\"config\":{\"parseConfig\":{");
    sb.append("\"blockOptions\":{");
    sb.append("\"text\":{\"agentic\":{\"enabled\":true},\"signatureDetectionEnabled\":true},");
    sb.append("\"tables\":{\"agentic\":{\"enabled\":true},\"tableHeaderContinuationEnabled\":true},");
    sb.append("\"figures\":{\"enabled\":true}");
    sb.append("},");
    sb.append("\"chunkingStrategy\":{\"type\":\"page\",\"options\":{}}");
    sb.append("}},\"next\":[{\"step\":\"split2\"}]},");

    // split2
    sb.append("{\"name\":\"split2\",\"type\":\"SPLIT\",\"config\":{\"splitterConfig\":{");
    sb.append("\"splitClassifications\":[");

    String[] classIds = {
        "splitter_classification1", "subdocument_type_45c", "subdocument_type_VxE", "subdocument_type_Cvy",
        "subdocument_type__MG", "subdocument_type_jHc", "subdocument_type_4mW", "subdocument_type_zwe",
        "subdocument_type_6cV", "subdocument_type_uC_", "subdocument_type_anp", "subdocument_type_R7E",
        "subdocument_type_PcP", "subdocument_type_Qqj", "subdocument_type_HgI", "subdocument_type_KmI",
        "subdocument_type_MDu", "subdocument_type_Uog", "subdocument_type_aDh", "subdocument_type_QSG",
        "subdocument_type_p8F", "subdocument_type_hsN", "subdocument_type_6Wm", "subdocument_type_dMz",
        "subdocument_type_6La", "subdocument_type_aKJ", "subdocument_type_KRI", "subdocument_type_6jD",
        "subdocument_type_KHi", "subdocument_type_K70", "subdocument_type_h5y", "subdocument_type_iPz",
        "subdocument_type_yh5", "subdocument_type_Z-j", "subdocument_type_-PC", "subdocument_type_VOq",
        "subdocument_type_On9", "subdocument_type_UEl", "subdocument_type_0_8", "subdocument_type_dZ3",
        "subdocument_type_PBZ", "subdocument_type_2br", "subdocument_type_MO6", "subdocument_type_Dgl",
        "subdocument_type_w1k"
    };

    String[] classTypes = {
        "other", "Loan Transmittal Cover Sheet", "Uniform Underwriting and Transmittal Summary",
        "Underwriting Approval Certificate", "Automated Underwriting Findings", "Uniform Residential Loan Application",
        "Demographic Information Addendum", "Loan Estimate", "Closing Disclosure", "Intent to Proceed",
        "Settlement Service Provider List", "ECOA Fair Lending Notice", "Homeownership Counseling Disclosure",
        "Borrower Certification and Authorization", "Tax Return Transcript Request", "Residential Mortgage Credit Report",
        "Credit Score Disclosure", "Letter of Explanation", "Undisclosed Debt Monitoring Report",
        "Earnings Statement / Pay Stub", "W-2 Wage and Tax Statement", "Written Verification of Employment",
        "Verbal Verification of Employment", "Tax Return Transcript", "Income Calculation Worksheet",
        "Bank Statement Checking", "Bank Statement Savings", "Brokerage Statement", "Retirement Account Statement",
        "Gift Letter", "Earnest Money Deposit Evidence", "Uniform Residential Appraisal Report",
        "UCDP Submission Summary Report", "Appraisal Invoice", "Flood Hazard Determination",
        "Title Insurance Commitment", "Closing Protection Letter", "Wire and Disbursement Instructions",
        "Homeowners Insurance Declaration Page", "Flood Insurance Exemption Notice",
        "Residential Purchase and Sale Agreement", "Seller Disclosure Notice", "Verification of Rent",
        "Government Photo ID", "Loan Officer Compensation Disclosure"
    };

    String[] classDescriptions = {
        "Use the `other` document type when the document can not clearly be classified into one of the described classifications.",
        "Cover page listing loan snapshot, borrower information, loan team, and package contents summary",
        "Standardized form summarizing borrower income, mortgage information, qualifying ratios, and underwriter comments",
        "Official conditional approval document listing prior-to-document and prior-to-funding conditions with status",
        "System-generated AUS findings report showing approve/eligible recommendation and risk assessment",
        "Multi-page standard mortgage application with borrower employment, income, assets, liabilities, and property information",
        "Government monitoring form capturing borrower race, ethnicity, and sex information",
        "Three page federal disclosure showing estimated loan terms, projected payments, and closing costs",
        "Five page federal form showing final loan terms and itemized closing costs",
        "Signed borrower acknowledgment of intent to proceed with loan application",
        "Written list of approved third party service providers",
        "Federal notice of equal credit opportunity rights and right to receive appraisal copy",
        "List of HUD approved housing counseling organizations",
        "Borrower certification that application is accurate and authorization to verify information",
        "IRS form authorizing lender to obtain tax transcripts directly from IRS",
        "Tri-merge credit report showing credit history, scores, and tradelines from all three bureaus",
        "Notice to home loan applicant disclosing credit scores used in underwriting decision",
        "Borrower written explanation for credit inquiries or derogatory items",
        "Soft pull credit refresh to identify any new debt incurred during loan process",
        "Recent pay stub showing gross earnings, deductions, and year to date totals",
        "Annual employer wage statement showing total compensation and withholdings",
        "Employer completed form verifying borrower employment, position, income, and start date",
        "Lender log documenting phone verification of borrower employment status",
        "IRS transcript of filed tax return showing income, AGI, and withholdings",
        "Underwriter worksheet documenting income calculation methodology and qualifying amounts",
        "Monthly checking account statement showing transactions, deposits, and ending balance",
        "Monthly savings account statement showing deposits and ending balance",
        "Investment account statement showing holdings, market value, and available assets",
        "401k or 403b statement showing account balance and vested amount",
        "Signed letter from donor documenting gift amount, relationship, and confirmation no repayment required",
        "Documentation of earnest money deposit showing funds cleared from borrower account",
        "Full appraisal report with property description, comparable sales, and appraised value",
        "Appraisal portal submission confirmation showing document file ID and status",
        "Invoice and delivery acknowledgment from appraisal management company",
        "Life of loan flood zone certification showing flood zone classification",
        "Commitment for title insurance with Schedule A property details and Schedule B exceptions",
        "Letter extending title underwriter protection to lender for closing agent acts",
        "Escrow agent wire instructions for funding disbursement",
        "Insurance policy declarations showing coverage amounts, premium, and mortgagee clause",
        "Lender notice that flood insurance is not required based on flood zone determination",
        "Executed contract between buyer and seller including purchase price, terms, and contingencies",
        "Seller's written disclosure of known property condition issues",
        "Documentation of borrower's current housing payment history",
        "Copies of borrower government issued photo identification per USA PATRIOT Act requirements",
        "Anti-steering and loan officer compensation disclosure form"
    };

    for (int i = 0; i < classIds.length; i++) {
      if (i > 0) sb.append(",");
      sb.append("{\"id\":\"").append(classIds[i]).append("\",");
      sb.append("\"type\":\"").append(classTypes[i]).append("\",");
      sb.append("\"description\":\"").append(escapeJson(classDescriptions[i])).append("\"}");
    }

    sb.append("]");
    sb.append("}},\"next\":[");

    for (int i = 0; i < classIds.length; i++) {
      if (i > 0) sb.append(",");
      sb.append("{\"step\":\"extraction3\",\"classificationId\":\"").append(classIds[i]).append("\"}");
    }

    sb.append("]},");

    // extraction3 with full schema
    sb.append("{\"name\":\"extraction3\",\"type\":\"EXTRACT\",\"config\":{\"extractorConfig\":{");
    sb.append("\"schema\":").append(buildSchemaJson());
    sb.append(",\"baseProcessor\":\"extraction_performance\",");
    sb.append("\"advancedOptions\":{\"reviewAgent\":{\"enabled\":false},\"advancedMultimodalEnabled\":false}");
    sb.append("}}}");

    sb.append("]");
    sb.append("}");
    return sb.toString();
  }

  private static String buildSchemaJson() {
    return "{\"type\":\"object\",\"required\":[\"state\",\"tax_year\",\"box_12_codes\",\"employee_name\",\"employer_name\",\"locality_name\",\"allocated_tips\",\"control_number\",\"retirement_plan\",\"employee_address\",\"employer_address\",\"local_income_tax\",\"state_income_tax\",\"other_information\",\"nonqualified_plans\",\"statutory_employee\",\"local_wages_tips_etc\",\"social_security_tips\",\"state_wages_tips_etc\",\"third_party_sick_pay\",\"medicare_tax_withheld\",\"social_security_wages\",\"wages_tips_other_comp\",\"dependent_care_benefits\",\"medicare_wages_and_tips\",\"employer_state_id_number\",\"federal_income_tax_withheld\",\"social_security_tax_withheld\",\"employer_identification_number\",\"employee_social_security_number\"],\"properties\":{\"state\":{\"type\":[\"string\",\"null\"],\"description\":\"The state in which the employer is located or where state wages and taxes are reported. May be labeled as 'State' or appear with the employer's address.\"},\"tax_year\":{\"type\":[\"string\",\"null\"],\"description\":\"The calendar year for which this wage and tax statement applies. This is the reporting year for the income and withholdings shown. Commonly appears as part of the document title or heading.\"},\"box_12_codes\":{\"type\":\"array\",\"items\":{\"type\":\"object\",\"required\":[\"code\",\"amount\",\"description\"],\"properties\":{\"code\":{\"type\":[\"string\",\"null\"],\"description\":\"The single-letter or letter-number code used in Box 12 to indicate the type of compensation, deferral, or benefit (e.g., D, E, AA, etc.).\"},\"amount\":{\"type\":[\"number\",\"null\"],\"description\":\"The monetary value or amount associated with this Box 12 code, if applicable.\"},\"description\":{\"type\":[\"string\",\"null\"],\"description\":\"A brief description of what the code represents, if available. May be present in document footnotes or instructions.\"}},\"additionalProperties\":false},\"description\":\"An array of code-value pairs reported in Box 12. Each entry represents a specific code (such as D, E, etc.) and the corresponding amount or value. These codes report various types of compensation, deferrals, or benefits. The codes and their meanings may vary by year and employer.\"},\"employee_name\":{\"type\":[\"string\",\"null\"],\"description\":\"The full legal name of the employee as reported on the wage and tax statement. Typically includes first name, middle initial, and last name, and may include suffixes. Commonly found near the employee's address.\"},\"employer_name\":{\"type\":[\"string\",\"null\"],\"description\":\"The legal name of the employer or company issuing this wage and tax statement. This is the entity that paid the employee and is responsible for reporting wages and withholdings.\"},\"locality_name\":{\"type\":[\"string\",\"null\"],\"description\":\"The name of the locality (city, county, or other jurisdiction) for which local wages and taxes are reported. May be labeled as 'Locality name' or 'Box 20'.\"},\"allocated_tips\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The amount of tips allocated to the employee by the employer, if applicable. May be labeled as 'Allocated tips' or 'Box 8'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"control_number\":{\"type\":[\"string\",\"null\"],\"description\":\"A unique control or reference number assigned to this wage and tax statement by the employer or payroll processor. Used for internal tracking and may appear as 'Control number' or similar.\"},\"retirement_plan\":{\"type\":[\"boolean\",\"null\"],\"description\":\"Indicates whether the employee was an active participant in an employer-sponsored retirement plan during the tax year. This is typically marked as a checkbox or indicator.\"},\"employee_address\":{\"type\":[\"string\",\"null\"],\"description\":\"The mailing address of the employee as reported on the wage and tax statement. May include street address, unit/apartment, city, state, and ZIP code. Can span multiple lines in some documents.\"},\"employer_address\":{\"type\":[\"string\",\"null\"],\"description\":\"The mailing address of the employer as reported on the wage and tax statement. May include street address, suite or unit, city, state, and ZIP code. Can span multiple lines.\"},\"local_income_tax\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total amount of local income tax withheld from the employee's pay for the tax year. May be labeled as 'Local income tax' or 'Box 19'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"state_income_tax\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total amount of state income tax withheld from the employee's pay for the tax year. May be labeled as 'State income tax' or 'Box 17'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"other_information\":{\"type\":[\"string\",\"null\"],\"description\":\"Any additional information or miscellaneous codes reported in Box 14 or similar sections. This may include state-specific codes, explanations, or other employer-provided notes.\"},\"nonqualified_plans\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total amount distributed to the employee from nonqualified deferred compensation plans. May be labeled as 'Nonqualified plans' or 'Box 11'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"statutory_employee\":{\"type\":[\"boolean\",\"null\"],\"description\":\"Indicates whether the employee is classified as a statutory employee for tax purposes. This is typically marked as a checkbox or indicator on the wage and tax statement.\"},\"local_wages_tips_etc\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total amount of wages, tips, and other compensation subject to local income tax for the tax year. May be labeled as 'Local wages, tips, etc.' or 'Box 18'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"social_security_tips\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total tips reported by the employee that are subject to Social Security tax. May be labeled as 'Social security tips' or 'Box 7'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"state_wages_tips_etc\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total amount of wages, tips, and other compensation subject to state income tax for the tax year. May be labeled as 'State wages, tips, etc.' or 'Box 16'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"third_party_sick_pay\":{\"type\":[\"boolean\",\"null\"],\"description\":\"Indicates whether the employee received third-party sick pay during the tax year. This is typically marked as a checkbox or indicator.\"},\"medicare_tax_withheld\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total amount of Medicare tax withheld from the employee's pay for the tax year. Often labeled as 'Medicare tax withheld' or 'Box 6'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"social_security_wages\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total wages subject to Social Security tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Social security wages' or 'Box 3'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"wages_tips_other_comp\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total taxable wages, tips, and other compensation paid to the employee for the tax year. This is the primary income amount reported for federal tax purposes, often labeled as 'Wages, tips, other comp.' or 'Box 1'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"dependent_care_benefits\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total amount of dependent care benefits provided to the employee, if any. May be labeled as 'Dependent care benefits' or 'Box 10'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"medicare_wages_and_tips\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total wages and tips subject to Medicare tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Medicare wages and tips' or 'Box 5'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"employer_state_id_number\":{\"type\":[\"string\",\"null\"],\"description\":\"The employer's state identification number as reported on the wage and tax statement. This is used for state tax reporting and may be labeled as 'Employer's state ID no.' or similar.\"},\"federal_income_tax_withheld\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total amount of federal income tax withheld from the employee's pay for the tax year. This is the sum reported to the federal tax authority, often labeled as 'Federal income tax withheld' or 'Box 2'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"social_security_tax_withheld\":{\"type\":\"object\",\"required\":[\"amount\",\"iso_4217_currency_code\"],\"properties\":{\"amount\":{\"type\":[\"number\",\"null\"]},\"iso_4217_currency_code\":{\"type\":[\"string\",\"null\"]}},\"description\":\"The total amount of Social Security tax withheld from the employee's pay for the tax year. Often labeled as 'Social security tax withheld' or 'Box 4'.\",\"extend:type\":\"currency\",\"additionalProperties\":false},\"employer_identification_number\":{\"type\":[\"string\",\"null\"],\"description\":\"The employer's federal Employer Identification Number (EIN), a nine-digit number often formatted as XX-XXXXXXX. Used for tax reporting purposes.\"},\"employee_social_security_number\":{\"type\":[\"string\",\"null\"],\"description\":\"The employee's Social Security Number (SSN) as reported on the wage and tax statement. This is a nine-digit identifier, often formatted as XXX-XX-XXXX. May be labeled as 'Employee's social security number' or similar.\"}},\"additionalProperties\":false}";
  }

  private static String escapeJson(String s) {
    return s.replace("\\", "\\\\").replace("\"", "\\\"").replace("\n", "\\n").replace("\r", "\\r");
  }

  public static void main(String[] args) {
    try {
      String workflowName = "Underwriting Package Processing Pipeline";
      System.out.println("Deploying \"" + workflowName + "\"…");

      String workflowJson = buildWorkflowJson();

      if (state.workflowId != null && !state.workflowId.isEmpty()) {
        System.out.println("✓ workflow already provisioned (" + state.workflowId + ") — updating steps");
        String stepsJson = "{\"steps\":" + workflowJson.substring(workflowJson.indexOf("\"steps\"") + 8, workflowJson.lastIndexOf("]") + 1) + "}";
        apiCall("POST", "/workflows/" + state.workflowId, stepsJson);
      } else {
        // Try to find existing workflow by name
        try {
          String listResponse = apiCall("GET", "/workflows?name=" + URLEncoder.encode(workflowName, StandardCharsets.UTF_8), null);
          String existingId = parseJsonField(listResponse, "id");
          if (existingId != null && !existingId.isEmpty()) {
            state.workflowId = existingId;
            saveState();
            System.out.println("✓ workflow \"" + workflowName + "\" found in your account (" + existingId + ") — updating steps");
            String stepsJson = "{\"steps\":" + workflowJson.substring(workflowJson.indexOf("\"steps\"") + 8, workflowJson.lastIndexOf("]") + 1) + "}";
            apiCall("POST", "/workflows/" + existingId, stepsJson);
          }
        } catch (Exception e) {
          // Lookup is best-effort; fall through to create
        }

        if (state.workflowId == null || state.workflowId.isEmpty()) {
          String createResponse = apiCall("POST", "/workflows", workflowJson);
          String wfId = parseJsonField(createResponse, "id");
          if (wfId == null || wfId.isEmpty()) {
            throw new Exception("Could not read created workflow id from response");
          }
          state.workflowId = wfId;
          saveState();
          System.out.println("+ created workflow (" + wfId + ")");
        }
      }

      // Deploy the current draft as a new version (best-effort)
      try {
        apiCall("POST", "/workflows/" + state.workflowId + "/versions", "{}");
      } catch (Exception e) {
        // Best-effort; some accounts may not require this
      }

      System.out.println("\nDone. Run documents through it with:");
      System.out.println("  POST " + API + "/workflow_runs  { workflow: { id: \"" + state.workflowId + "\" }, file: { url: \"https://…\" } }");
      System.out.println("Or open the workflow in the Extend dashboard to review and deploy it.");
    } catch (Exception e) {
      System.err.println(e.getMessage() != null ? e.getMessage() : e.toString());
      System.exit(1);
    }
  }
}
// This script uses the Extend REST API directly because Extend has no official Go SDK yet.
// Deploy the "Underwriting Package" 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/underwriting-package.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)
//   go run provision.go
//
// Generated by doc1 (template: underwriting-package).

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"`
}

var (
	apiKey   string
	stateDir string
	stateFile string
	state    State
)

func init() {
	apiKey = os.Getenv("EXTEND_API_KEY")
	if apiKey == "" {
		fmt.Fprintf(os.Stderr, "Set EXTEND_API_KEY first.\n")
		os.Exit(1)
	}

	cwd, err := os.Getwd()
	if err != nil {
		fmt.Fprintf(os.Stderr, "Failed to get working directory: %v\n", err)
		os.Exit(1)
	}
	stateDir = filepath.Join(cwd, ".extend")
	stateFile = filepath.Join(stateDir, "underwriting-package.json")

	// Load existing state if it exists
	if data, err := os.ReadFile(stateFile); err == nil {
		json.Unmarshal(data, &state)
	}
}

func saveState() error {
	if err := os.MkdirAll(stateDir, 0755); err != nil {
		return err
	}
	data, err := json.MarshalIndent(state, "", "  ")
	if err != nil {
		return err
	}
	return os.WriteFile(stateFile, data, 0644)
}

func apiCall(method, pathName string, body interface{}) (map[string]interface{}, error) {
	var reqBody io.Reader
	if body != nil {
		data, err := json.Marshal(body)
		if err != nil {
			return nil, err
		}
		reqBody = bytes.NewReader(data)
	}

	req, err := http.NewRequest(method, API+pathName, reqBody)
	if err != nil {
		return nil, err
	}

	req.Header.Set("Authorization", "Bearer "+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, err := io.ReadAll(resp.Body)
	if err != nil {
		return nil, err
	}

	var data map[string]interface{}
	json.Unmarshal(respBody, &data)

	if resp.StatusCode >= 400 {
		respStr := string(respBody)
		if len(respStr) > 300 {
			respStr = respStr[:300]
		}
		return nil, fmt.Errorf("%s %s failed (%d): %s", method, pathName, resp.StatusCode, respStr)
	}

	return data, nil
}

var workflow = map[string]interface{}{
	"name": "Underwriting Package Processing Pipeline",
	"steps": []map[string]interface{}{
		{
			"name": "startTrigger1",
			"type": "TRIGGER",
			"next": []map[string]interface{}{
				{"step": "parse1"},
			},
		},
		{
			"name": "parse1",
			"type": "PARSE",
			"config": map[string]interface{}{
				"parseConfig": map[string]interface{}{
					"blockOptions": map[string]interface{}{
						"text": map[string]interface{}{
							"agentic": map[string]interface{}{
								"enabled": true,
							},
							"signatureDetectionEnabled": true,
						},
						"tables": map[string]interface{}{
							"agentic": map[string]interface{}{
								"enabled": true,
							},
							"tableHeaderContinuationEnabled": true,
						},
						"figures": map[string]interface{}{
							"enabled": true,
						},
					},
					"chunkingStrategy": map[string]interface{}{
						"type":    "page",
						"options": map[string]interface{}{},
					},
				},
			},
			"next": []map[string]interface{}{
				{"step": "split2"},
			},
		},
		{
			"name": "split2",
			"type": "SPLIT",
			"config": map[string]interface{}{
				"splitterConfig": map[string]interface{}{
					"splitClassifications": []map[string]interface{}{
						{"id": "splitter_classification1", "type": "other", "description": "Use the `other` document type when the document can not clearly be classified into one of the described classifications."},
						{"id": "subdocument_type_45c", "type": "Loan Transmittal Cover Sheet", "description": "Cover page listing loan snapshot, borrower information, loan team, and package contents summary"},
						{"id": "subdocument_type_VxE", "type": "Uniform Underwriting and Transmittal Summary", "description": "Standardized form summarizing borrower income, mortgage information, qualifying ratios, and underwriter comments"},
						{"id": "subdocument_type_Cvy", "type": "Underwriting Approval Certificate", "description": "Official conditional approval document listing prior-to-document and prior-to-funding conditions with status"},
						{"id": "subdocument_type__MG", "type": "Automated Underwriting Findings", "description": "System-generated AUS findings report showing approve/eligible recommendation and risk assessment"},
						{"id": "subdocument_type_jHc", "type": "Uniform Residential Loan Application", "description": "Multi-page standard mortgage application with borrower employment, income, assets, liabilities, and property information"},
						{"id": "subdocument_type_4mW", "type": "Demographic Information Addendum", "description": "Government monitoring form capturing borrower race, ethnicity, and sex information"},
						{"id": "subdocument_type_zwe", "type": "Loan Estimate", "description": "Three page federal disclosure showing estimated loan terms, projected payments, and closing costs"},
						{"id": "subdocument_type_6cV", "type": "Closing Disclosure", "description": "Five page federal form showing final loan terms and itemized closing costs"},
						{"id": "subdocument_type_uC_", "type": "Intent to Proceed", "description": "Signed borrower acknowledgment of intent to proceed with loan application"},
						{"id": "subdocument_type_anp", "type": "Settlement Service Provider List", "description": "Written list of approved third party service providers"},
						{"id": "subdocument_type_R7E", "type": "ECOA Fair Lending Notice", "description": "Federal notice of equal credit opportunity rights and right to receive appraisal copy"},
						{"id": "subdocument_type_PcP", "type": "Homeownership Counseling Disclosure", "description": "List of HUD approved housing counseling organizations"},
						{"id": "subdocument_type_Qqj", "type": "Borrower Certification and Authorization", "description": "Borrower certification that application is accurate and authorization to verify information"},
						{"id": "subdocument_type_HgI", "type": "Tax Return Transcript Request", "description": "IRS form authorizing lender to obtain tax transcripts directly from IRS"},
						{"id": "subdocument_type_KmI", "type": "Residential Mortgage Credit Report", "description": "Tri-merge credit report showing credit history, scores, and tradelines from all three bureaus"},
						{"id": "subdocument_type_MDu", "type": "Credit Score Disclosure", "description": "Notice to home loan applicant disclosing credit scores used in underwriting decision"},
						{"id": "subdocument_type_Uog", "type": "Letter of Explanation", "description": "Borrower written explanation for credit inquiries or derogatory items"},
						{"id": "subdocument_type_aDh", "type": "Undisclosed Debt Monitoring Report", "description": "Soft pull credit refresh to identify any new debt incurred during loan process"},
						{"id": "subdocument_type_QSG", "type": "Earnings Statement / Pay Stub", "description": "Recent pay stub showing gross earnings, deductions, and year to date totals"},
						{"id": "subdocument_type_p8F", "type": "W-2 Wage and Tax Statement", "description": "Annual employer wage statement showing total compensation and withholdings"},
						{"id": "subdocument_type_hsN", "type": "Written Verification of Employment", "description": "Employer completed form verifying borrower employment, position, income, and start date"},
						{"id": "subdocument_type_6Wm", "type": "Verbal Verification of Employment", "description": "Lender log documenting phone verification of borrower employment status"},
						{"id": "subdocument_type_dMz", "type": "Tax Return Transcript", "description": "IRS transcript of filed tax return showing income, AGI, and withholdings"},
						{"id": "subdocument_type_6La", "type": "Income Calculation Worksheet", "description": "Underwriter worksheet documenting income calculation methodology and qualifying amounts"},
						{"id": "subdocument_type_aKJ", "type": "Bank Statement Checking", "description": "Monthly checking account statement showing transactions, deposits, and ending balance"},
						{"id": "subdocument_type_KRI", "type": "Bank Statement Savings", "description": "Monthly savings account statement showing deposits and ending balance"},
						{"id": "subdocument_type_6jD", "type": "Brokerage Statement", "description": "Investment account statement showing holdings, market value, and available assets"},
						{"id": "subdocument_type_KHi", "type": "Retirement Account Statement", "description": "401k or 403b statement showing account balance and vested amount"},
						{"id": "subdocument_type_K70", "type": "Gift Letter", "description": "Signed letter from donor documenting gift amount, relationship, and confirmation no repayment required"},
						{"id": "subdocument_type_h5y", "type": "Earnest Money Deposit Evidence", "description": "Documentation of earnest money deposit showing funds cleared from borrower account"},
						{"id": "subdocument_type_iPz", "type": "Uniform Residential Appraisal Report", "description": "Full appraisal report with property description, comparable sales, and appraised value"},
						{"id": "subdocument_type_yh5", "type": "UCDP Submission Summary Report", "description": "Appraisal portal submission confirmation showing document file ID and status"},
						{"id": "subdocument_type_Z-j", "type": "Appraisal Invoice", "description": "Invoice and delivery acknowledgment from appraisal management company"},
						{"id": "subdocument_type_-PC", "type": "Flood Hazard Determination", "description": "Life of loan flood zone certification showing flood zone classification"},
						{"id": "subdocument_type_VOq", "type": "Title Insurance Commitment", "description": "Commitment for title insurance with Schedule A property details and Schedule B exceptions"},
						{"id": "subdocument_type_On9", "type": "Closing Protection Letter", "description": "Letter extending title underwriter protection to lender for closing agent acts"},
						{"id": "subdocument_type_UEl", "type": "Wire and Disbursement Instructions", "description": "Escrow agent wire instructions for funding disbursement"},
						{"id": "subdocument_type_0_8", "type": "Homeowners Insurance Declaration Page", "description": "Insurance policy declarations showing coverage amounts, premium, and mortgagee clause"},
						{"id": "subdocument_type_dZ3", "type": "Flood Insurance Exemption Notice", "description": "Lender notice that flood insurance is not required based on flood zone determination"},
						{"id": "subdocument_type_PBZ", "type": "Residential Purchase and Sale Agreement", "description": "Executed contract between buyer and seller including purchase price, terms, and contingencies"},
						{"id": "subdocument_type_2br", "type": "Seller Disclosure Notice", "description": "Seller's written disclosure of known property condition issues"},
						{"id": "subdocument_type_MO6", "type": "Verification of Rent", "description": "Documentation of borrower's current housing payment history"},
						{"id": "subdocument_type_Dgl", "type": "Government Photo ID", "description": "Copies of borrower government issued photo identification per USA PATRIOT Act requirements"},
						{"id": "subdocument_type_w1k", "type": "Loan Officer Compensation Disclosure", "description": "Anti-steering and loan officer compensation disclosure form"},
					},
				},
			},
			"next": buildSplitNextSteps(),
		},
		{
			"name": "extraction3",
			"type": "EXTRACT",
			"config": map[string]interface{}{
				"extractorConfig": map[string]interface{}{
					"schema": extractionSchema(),
					"baseProcessor": "extraction_performance",
					"advancedOptions": map[string]interface{}{
						"reviewAgent": map[string]interface{}{
							"enabled": false,
						},
						"advancedMultimodalEnabled": false,
					},
				},
			},
		},
	},
}

func buildSplitNextSteps() []map[string]interface{} {
	classificationIDs := []string{
		"splitter_classification1", "subdocument_type_45c", "subdocument_type_VxE", "subdocument_type_Cvy",
		"subdocument_type__MG", "subdocument_type_jHc", "subdocument_type_4mW", "subdocument_type_zwe",
		"subdocument_type_6cV", "subdocument_type_uC_", "subdocument_type_anp", "subdocument_type_R7E",
		"subdocument_type_PcP", "subdocument_type_Qqj", "subdocument_type_HgI", "subdocument_type_KmI",
		"subdocument_type_MDu", "subdocument_type_Uog", "subdocument_type_aDh", "subdocument_type_QSG",
		"subdocument_type_p8F", "subdocument_type_hsN", "subdocument_type_6Wm", "subdocument_type_dMz",
		"subdocument_type_6La", "subdocument_type_aKJ", "subdocument_type_KRI", "subdocument_type_6jD",
		"subdocument_type_KHi", "subdocument_type_K70", "subdocument_type_h5y", "subdocument_type_iPz",
		"subdocument_type_yh5", "subdocument_type_Z-j", "subdocument_type_-PC", "subdocument_type_VOq",
		"subdocument_type_On9", "subdocument_type_UEl", "subdocument_type_0_8", "subdocument_type_dZ3",
		"subdocument_type_PBZ", "subdocument_type_2br", "subdocument_type_MO6", "subdocument_type_Dgl",
		"subdocument_type_w1k",
	}
	var steps []map[string]interface{}
	for _, id := range classificationIDs {
		steps = append(steps, map[string]interface{}{
			"step":               "extraction3",
			"classificationId":   id,
		})
	}
	return steps
}

func extractionSchema() map[string]interface{} {
	return map[string]interface{}{
		"type": "object",
		"required": []string{
			"state", "tax_year", "box_12_codes", "employee_name", "employer_name", "locality_name",
			"allocated_tips", "control_number", "retirement_plan", "employee_address", "employer_address",
			"local_income_tax", "state_income_tax", "other_information", "nonqualified_plans",
			"statutory_employee", "local_wages_tips_etc", "social_security_tips", "state_wages_tips_etc",
			"third_party_sick_pay", "medicare_tax_withheld", "social_security_wages", "wages_tips_other_comp",
			"dependent_care_benefits", "medicare_wages_and_tips", "employer_state_id_number",
			"federal_income_tax_withheld", "social_security_tax_withheld", "employer_identification_number",
			"employee_social_security_number",
		},
		"properties": map[string]interface{}{
			"state": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The state in which the employer is located or where state wages and taxes are reported. May be labeled as 'State' or appear with the employer's address.",
			},
			"tax_year": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The calendar year for which this wage and tax statement applies. This is the reporting year for the income and withholdings shown. Commonly appears as part of the document title or heading.",
			},
			"box_12_codes": map[string]interface{}{
				"type": "array",
				"items": map[string]interface{}{
					"type": "object",
					"required": []string{"code", "amount", "description"},
					"properties": map[string]interface{}{
						"code": map[string]interface{}{
							"type": []string{"string", "null"},
							"description": "The single-letter or letter-number code used in Box 12 to indicate the type of compensation, deferral, or benefit (e.g., D, E, AA, etc.).",
						},
						"amount": map[string]interface{}{
							"type": []string{"number", "null"},
							"description": "The monetary value or amount associated with this Box 12 code, if applicable.",
						},
						"description": map[string]interface{}{
							"type": []string{"string", "null"},
							"description": "A brief description of what the code represents, if available. May be present in document footnotes or instructions.",
						},
					},
					"additionalProperties": false,
				},
				"description": "An array of code-value pairs reported in Box 12. Each entry represents a specific code (such as D, E, etc.) and the corresponding amount or value. These codes report various types of compensation, deferrals, or benefits. The codes and their meanings may vary by year and employer.",
			},
			"employee_name": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The full legal name of the employee as reported on the wage and tax statement. Typically includes first name, middle initial, and last name, and may include suffixes. Commonly found near the employee's address.",
			},
			"employer_name": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The legal name of the employer or company issuing this wage and tax statement. This is the entity that paid the employee and is responsible for reporting wages and withholdings.",
			},
			"locality_name": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The name of the locality (city, county, or other jurisdiction) for which local wages and taxes are reported. May be labeled as 'Locality name' or 'Box 20'.",
			},
			"allocated_tips": currencyField("The amount of tips allocated to the employee by the employer, if applicable. May be labeled as 'Allocated tips' or 'Box 8'."),
			"control_number": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "A unique control or reference number assigned to this wage and tax statement by the employer or payroll processor. Used for internal tracking and may appear as 'Control number' or similar.",
			},
			"retirement_plan": map[string]interface{}{
				"type": []string{"boolean", "null"},
				"description": "Indicates whether the employee was an active participant in an employer-sponsored retirement plan during the tax year. This is typically marked as a checkbox or indicator.",
			},
			"employee_address": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The mailing address of the employee as reported on the wage and tax statement. May include street address, unit/apartment, city, state, and ZIP code. Can span multiple lines in some documents.",
			},
			"employer_address": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The mailing address of the employer as reported on the wage and tax statement. May include street address, suite or unit, city, state, and ZIP code. Can span multiple lines.",
			},
			"local_income_tax": currencyField("The total amount of local income tax withheld from the employee's pay for the tax year. May be labeled as 'Local income tax' or 'Box 19'."),
			"state_income_tax": currencyField("The total amount of state income tax withheld from the employee's pay for the tax year. May be labeled as 'State income tax' or 'Box 17'."),
			"other_information": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "Any additional information or miscellaneous codes reported in Box 14 or similar sections. This may include state-specific codes, explanations, or other employer-provided notes.",
			},
			"nonqualified_plans": currencyField("The total amount distributed to the employee from nonqualified deferred compensation plans. May be labeled as 'Nonqualified plans' or 'Box 11'."),
			"statutory_employee": map[string]interface{}{
				"type": []string{"boolean", "null"},
				"description": "Indicates whether the employee is classified as a statutory employee for tax purposes. This is typically marked as a checkbox or indicator on the wage and tax statement.",
			},
			"local_wages_tips_etc": currencyField("The total amount of wages, tips, and other compensation subject to local income tax for the tax year. May be labeled as 'Local wages, tips, etc.' or 'Box 18'."),
			"social_security_tips": currencyField("The total tips reported by the employee that are subject to Social Security tax. May be labeled as 'Social security tips' or 'Box 7'."),
			"state_wages_tips_etc": currencyField("The total amount of wages, tips, and other compensation subject to state income tax for the tax year. May be labeled as 'State wages, tips, etc.' or 'Box 16'."),
			"third_party_sick_pay": map[string]interface{}{
				"type": []string{"boolean", "null"},
				"description": "Indicates whether the employee received third-party sick pay during the tax year. This is typically marked as a checkbox or indicator.",
			},
			"medicare_tax_withheld": currencyField("The total amount of Medicare tax withheld from the employee's pay for the tax year. Often labeled as 'Medicare tax withheld' or 'Box 6'."),
			"social_security_wages": currencyField("The total wages subject to Social Security tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Social security wages' or 'Box 3'."),
			"wages_tips_other_comp": currencyField("The total taxable wages, tips, and other compensation paid to the employee for the tax year. This is the primary income amount reported for federal tax purposes, often labeled as 'Wages, tips, other comp.' or 'Box 1'."),
			"dependent_care_benefits": currencyField("The total amount of dependent care benefits provided to the employee, if any. May be labeled as 'Dependent care benefits' or 'Box 10'."),
			"medicare_wages_and_tips": currencyField("The total wages and tips subject to Medicare tax for the tax year. This may differ from total wages due to limits or exclusions. Often labeled as 'Medicare wages and tips' or 'Box 5'."),
			"employer_state_id_number": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The employer's state identification number as reported on the wage and tax statement. This is used for state tax reporting and may be labeled as 'Employer's state ID no.' or similar.",
			},
			"federal_income_tax_withheld": currencyField("The total amount of federal income tax withheld from the employee's pay for the tax year. This is the sum reported to the federal tax authority, often labeled as 'Federal income tax withheld' or 'Box 2'."),
			"social_security_tax_withheld": currencyField("The total amount of Social Security tax withheld from the employee's pay for the tax year. Often labeled as 'Social security tax withheld' or 'Box 4'."),
			"employer_identification_number": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The employer's federal Employer Identification Number (EIN), a nine-digit number often formatted as XX-XXXXXXX. Used for tax reporting purposes.",
			},
			"employee_social_security_number": map[string]interface{}{
				"type": []string{"string", "null"},
				"description": "The employee's Social Security Number (SSN) as reported on the wage and tax statement. This is a nine-digit identifier, often formatted as XXX-XX-XXXX. May be labeled as 'Employee's social security number' or similar.",
			},
		},
		"additionalProperties": false,
	}
}

func currencyField(description string) map[string]interface{} {
	return map[string]interface{}{
		"type": "object",
		"required": []string{"amount", "iso_4217_currency_code"},
		"properties": map[string]interface{}{
			"amount": map[string]interface{}{
				"type": []string{"number", "null"},
			},
			"iso_4217_currency_code": map[string]interface{}{
				"type": []string{"string", "null"},
			},
		},
		"description": description,
		"extend:type": "currency",
		"additionalProperties": false,
	}
}

func main() {
	fmt.Printf("Deploying \"%s\"…\n", workflow["name"])

	if state.WorkflowID != "" {
		fmt.Printf("✓ workflow already provisioned (%s) — updating steps\n", state.WorkflowID)
		_, err := apiCall("POST", "/workflows/"+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 with same name
		query := url.QueryEscape(workflow["name"].(string))
		list, err := apiCall("GET", "/workflows?name="+query, nil)
		if err == nil {
			var items []map[string]interface{}
			if data, ok := list["data"].([]interface{}); ok {
				for _, item := range data {
					if m, ok := item.(map[string]interface{}); ok {
						items = append(items, m)
					}
				}
			} else if data, ok := list["items"].([]interface{}); ok {
				for _, item := range data {
					if m, ok := item.(map[string]interface{}); ok {
						items = append(items, m)
					}
				}
			}

			for _, item := range items {
				if name, ok := item["name"].(string); ok && name == workflow["name"].(string) {
					if id, ok := item["id"].(string); ok {
						state.WorkflowID = id
						saveState()
						fmt.Printf("✓ workflow \"%s\" found in your account (%s) — updating steps\n", workflow["name"], id)
						_, err := apiCall("POST", "/workflows/"+id, map[string]interface{}{
							"steps": workflow["steps"],
						})
						if err != nil {
							fmt.Fprintf(os.Stderr, "Error: %v\n", err)
							os.Exit(1)
						}
						break
					}
				}
			}
		}

		if state.WorkflowID == "" {
			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.Fprintf(os.Stderr, "Error: Could not read created workflow id from response\n")
				os.Exit(1)
			}

			state.WorkflowID = wfID
			saveState()
			fmt.Printf("+ created workflow (%s)\n", wfID)
		}
	}

	// Deploy the current draft as a new version (best-effort)
	apiCall("POST", "/workflows/"+state.WorkflowID+"/versions", 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.")
}

Frequently Asked Questions (FAQ)

For underwriting (high-stakes decisions), flag any extraction result with confidence < 0.85 for human verification; underwriting packages often mix scanned and digital content, so `baseProcessor: "extraction_performance"` with a human-in-the-loop at 85% threshold balances speed and accuracy.
Parse the document with `mode: "agentic_ocr"` to get clean markdown with preserved table structure, then Extract using an array schema for `line_items` or `schedule_entries`
Use async (`createAndPoll` with `mode: "agentic_ocr"`) for batches > 10 documents or packages > 20 pages; sync works fine for single packages under 10 pages with clean digital PDFs
Tags
MortgageUnderwritingResidential LoanComplianceLoan Approval
About this template

A comprehensive residential mortgage underwriting package containing all required documentation for loan approval and closing. Includes borrower application materials, underwriting certifications, compliance disclosures, financial verification, and property appraisal summaries organized in standardized sections.

Document formats
  • PDF
  • Word / DOCX
Requirements
  • Long tables
  • 1k+ pages
  • Complex layouts

Relevant templates for Financial & Banking

  1. 01
    Driver's License ExtractorParse → Extract
    Extracts personal identification and licensing data from driver license documents.
    PDFImages & Scanswww.extend.ai/templates/driver-license-template
  2. 02
    Receipt ExtractorParse → Extract
    Extracts itemized sales, pricing, GST tax, and payment details from retail receipts.
    PDFImages & Scanswww.extend.ai/templates/receipt-parse-extract
  3. 03
    Bank Statement ExtractorParse → Extract
    Extracts account summaries, balances, deposits, NSF flags, and transaction details from bank statements.
    PDFImages & Scanswww.extend.ai/templates/bank-statement
  4. 04
    Vendor Invoice ExtractorParse → Extract
    Extracts charges, billing details, line items, totals, and due dates vendor invoices.
    PDFImages & Scanswww.extend.ai/templates/vendor-invoice
  5. 05
    Pay Stub ExtractorParse → Extract
    Extracts employee earnings, deductions, taxes, and net pay from pay stubs.
    PDFwww.extend.ai/templates/pay-stub
  6. 06
    Check ExtractorParse → Extract
    Extracts check details including payee, amount, date, and bank routing information.
    PDFImages & Scanswww.extend.ai/templates/check
  7. 07
    Wire Transfer Instructions ExtractorParse → Extract
    Extracts wire transfer procedures, contact info, and operational hours from banking guides.
    PDFWord / DOCXwww.extend.ai/templates/wire-transfer-instructions
  8. 08
    Onboarding Package ExtractorParse → Extract
    Extracts account summaries, transaction details, and balances from bank statements.
    PDFImages & Scanswww.extend.ai/templates/personal-bank-statement