> ## Documentation Index
> Fetch the complete documentation index at: https://docs.parsefy.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Extract

> Extract structured data from financial documents

## Overview

The `/v1/extract` endpoint is the primary way to extract structured data from financial documents (invoices, receipts, bills). It processes PDF and DOCX files according to your JSON Schema definition and returns validated JSON with field-level confidence and evidence.

<Info>
  **Our goal: 0% silent errors.** You get validated output with field-level evidence, or clear failure reasons; never unreliable data silently.
</Info>

## Request

<ParamField body="file" type="file" required>
  The document to extract data from.

  * **Supported formats**: PDF (`.pdf`), Microsoft Word (`.docx`)
  * **Maximum size**: 10 MB
</ParamField>

<ParamField body="output_schema" type="string" required>
  A JSON Schema string defining the structure of data to extract.

  See the [Schema Guide](/learn/schema-basics) for detailed documentation.

  <Warning>
    **Important:** Fields in the `required` array that return `null` or fall below `confidence_threshold` trigger the fallback model (Tier 2), which is more expensive.
  </Warning>
</ParamField>

<ParamField body="confidence_threshold" type="number" default="0.85">
  Minimum confidence score (0.0 to 1.0) required before accepting Tier 1 results.

  * **Lower values** (e.g., 0.70): Faster and cheaper (accepts Tier 1 results more often)
  * **Higher values** (e.g., 0.95): More accurate but more expensive (triggers Tier 2 fallback more often)

  **Default:** `0.85`
</ParamField>

<ParamField body="enable_verification" type="boolean" default="false">
  Enable math verification to ensure extracted numeric data is mathematically consistent.

  When enabled, Parsefy automatically:

  * Verifies totals match subtotals + tax
  * Validates line item sums
  * Performs shadow extraction for single-field verification

  **Default:** `false`
</ParamField>

<ParamField header="Authorization" type="string" required>
  Bearer token authentication.

  Format: `Bearer pk_your_api_key`
</ParamField>

## Response

<ResponseField name="object" type="object">
  The extracted data matching your schema.

  <Expandable title="properties">
    <ResponseField name="_meta" type="object">
      Quality metrics and field-level evidence for the extraction.

      <Expandable title="properties">
        <ResponseField name="confidence_score" type="number">
          Overall confidence level from 0.0 to 1.0
        </ResponseField>

        <ResponseField name="field_confidence" type="array">
          Per-field confidence with evidence

          <Expandable title="items">
            <ResponseField name="field" type="string">
              JSON path to the field (e.g., `$.invoice_number`)
            </ResponseField>

            <ResponseField name="score" type="number">
              Confidence score (0.0 to 1.0)
            </ResponseField>

            <ResponseField name="reason" type="string">
              Explanation: "Exact match", "Inferred from header", etc.
            </ResponseField>

            <ResponseField name="page" type="integer">
              Page number where the value was found
            </ResponseField>

            <ResponseField name="text" type="string">
              Source text evidence from the document
            </ResponseField>
          </Expandable>
        </ResponseField>

        <ResponseField name="issues" type="array">
          Array of issue descriptions (strings)
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="metadata" type="object">
  Processing information.

  <Expandable title="properties">
    <ResponseField name="processing_time_ms" type="integer">
      Total processing time in milliseconds
    </ResponseField>

    <ResponseField name="credits" type="integer">
      Credits used (\~1 per page, more if fallback triggered)
    </ResponseField>

    <ResponseField name="fallback_triggered" type="boolean">
      Whether the fallback model (Tier 2) was used
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="verification" type="object">
  Math verification results (only present if `enable_verification` was true).

  <Expandable title="properties">
    <ResponseField name="status" type="string">
      Overall status: `PASSED`, `FAILED`, `PARTIAL`, `CANNOT_VERIFY`, or `NO_RULES`
    </ResponseField>

    <ResponseField name="checks_passed" type="integer">
      Number of verification checks that passed
    </ResponseField>

    <ResponseField name="checks_failed" type="integer">
      Number of verification checks that failed
    </ResponseField>

    <ResponseField name="cannot_verify_count" type="integer">
      Number of checks that could not be verified
    </ResponseField>

    <ResponseField name="checks_run" type="array">
      Detailed results for each verification check

      <Expandable title="items">
        <ResponseField name="type" type="string">
          Type of check: `HORIZONTAL_SUM` or `VERTICAL_SUM`
        </ResponseField>

        <ResponseField name="status" type="string">
          Check status: `PASSED`, `FAILED`, or `CANNOT_VERIFY`
        </ResponseField>

        <ResponseField name="fields" type="array">
          Fields involved in this check
        </ResponseField>

        <ResponseField name="passed" type="boolean">
          Whether the check passed
        </ResponseField>

        <ResponseField name="delta" type="number">
          Difference between expected and actual values
        </ResponseField>

        <ResponseField name="expected" type="number">
          Expected value from the verification rule
        </ResponseField>

        <ResponseField name="actual" type="number">
          Actual value extracted from the document
        </ResponseField>
      </Expandable>
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="error" type="object">
  Present only if extraction failed.

  <Expandable title="properties">
    <ResponseField name="code" type="string">
      Error code: `EXTRACTION_FAILED`, `LLM_ERROR`, `PARSING_ERROR`, `TIMEOUT_ERROR`
    </ResponseField>

    <ResponseField name="message" type="string">
      Human-readable error message
    </ResponseField>
  </Expandable>
</ResponseField>

## Examples

### Basic Invoice Extraction with Confidence Threshold

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.parsefy.io/v1/extract" \
    -H "Authorization: Bearer pk_your_api_key" \
    -F "file=@invoice.pdf" \
    -F 'output_schema={
      "type": "object",
      "properties": {
        "invoice_number": {
          "type": "string",
          "description": "The invoice number"
        },
        "date": {
          "type": "string",
          "description": "Invoice date"
        },
        "total": {
          "type": "number",
          "description": "Total amount including tax"
        },
        "vendor": {
          "type": "string",
          "description": "Vendor name"
        }
      },
      "required": ["invoice_number", "total"]
    }' \
    -F "confidence_threshold=0.85"
  ```

  ```python Python theme={null}
  from parsefy import Parsefy
  from pydantic import BaseModel, Field

  client = Parsefy()

  class Invoice(BaseModel):
      # REQUIRED
      invoice_number: str = Field(description="The invoice number")
      total: float = Field(description="Total amount including tax")
      
      # OPTIONAL
      date: str | None = Field(default=None, description="Invoice date")
      vendor: str | None = Field(default=None, description="Vendor name")

  result = client.extract(
      file="invoice.pdf",
      schema=Invoice,
      confidence_threshold=0.85
  )

  if result.error is None:
      print(f"Invoice #{result.data.invoice_number}")
      print(f"Total: ${result.data.total}")
      print(f"Confidence: {result.metadata.confidence_score}")
  ```

  ```typescript TypeScript theme={null}
  import { Parsefy } from 'parsefy';
  import * as z from 'zod';

  const client = new Parsefy();

  const invoiceSchema = z.object({
    // REQUIRED
    invoice_number: z.string().describe('The invoice number'),
    total: z.number().describe('Total amount including tax'),
    
    // OPTIONAL
    date: z.string().optional().describe('Invoice date'),
    vendor: z.string().optional().describe('Vendor name'),
  });

  const { object, error, metadata } = await client.extract({
    file: './invoice.pdf',
    schema: invoiceSchema,
    confidenceThreshold: 0.85,
  });

  if (!error && object) {
    console.log(`Invoice #${object.invoice_number}`);
    console.log(`Total: $${object.total}`);
    console.log(`Confidence: ${metadata.confidenceScore}`);
  }
  ```
</CodeGroup>

### Response with Field-Level Confidence

```json theme={null}
{
  "object": {
    "invoice_number": "INV-2024-0042",
    "date": "01/15/2024",
    "subtotal": 1150.00,
    "tax": 100.00,
    "total": 1250.00,
    "vendor": "Acme Corp",
    "_meta": {
      "confidence_score": 0.94,
      "field_confidence": [
        { "field": "$.invoice_number", "score": 0.98, "reason": "Exact match", "page": 1, "text": "Invoice # INV-2024-0042" },
        { "field": "$.date", "score": 0.95, "reason": "Exact match", "page": 1, "text": "Date: 01/15/2024" },
        { "field": "$.subtotal", "score": 0.95, "reason": "Exact match", "page": 1, "text": "Subtotal: $1,150.00" },
        { "field": "$.tax", "score": 0.95, "reason": "Exact match", "page": 1, "text": "Tax: $100.00" },
        { "field": "$.total", "score": 0.92, "reason": "Formatting ambiguous", "page": 1, "text": "Total: $1,250.00" },
        { "field": "$.vendor", "score": 0.90, "reason": "Inferred from header", "page": 1, "text": "Acme Corp" }
      ],
      "issues": []
    }
  },
  "metadata": {
    "processing_time_ms": 2340,
    "credits": 1,
    "fallback_triggered": false
  },
  "verification": {
    "status": "PASSED",
    "checks_passed": 1,
    "checks_failed": 0,
    "cannot_verify_count": 0,
    "checks_run": [
      {
        "type": "HORIZONTAL_SUM",
        "status": "PASSED",
        "fields": ["total", "subtotal", "tax"],
        "passed": true,
        "delta": 0.0,
        "expected": 1250.00,
        "actual": 1250.00
      }
    ]
  }
}
```

### Complex Schema with Line Items

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://api.parsefy.io/v1/extract" \
    -H "Authorization: Bearer pk_your_api_key" \
    -F "file=@invoice.pdf" \
    -F 'output_schema={
      "type": "object",
      "properties": {
        "invoice_number": {"type": "string", "description": "Invoice number"},
        "vendor": {
          "type": "object",
          "properties": {
            "name": {"type": "string", "description": "Company name"},
            "address": {"type": "string", "description": "Address"}
          }
        },
        "line_items": {
          "type": "array",
          "description": "Line items on the invoice",
          "items": {
            "type": "object",
            "properties": {
              "description": {"type": "string"},
              "quantity": {"type": "integer"},
              "unit_price": {"type": "number"},
              "amount": {"type": "number"}
            }
          }
        },
        "subtotal": {"type": "number"},
        "tax": {"type": "number"},
        "total": {"type": "number", "description": "Total amount due"}
      },
      "required": ["invoice_number", "total", "line_items"]
    }' \
    -F "confidence_threshold=0.85"
  ```

  ```python Python theme={null}
  from parsefy import Parsefy
  from pydantic import BaseModel, Field

  client = Parsefy()

  class Vendor(BaseModel):
      name: str = Field(description="Company name")
      address: str | None = Field(default=None, description="Address")

  class LineItem(BaseModel):
      description: str = Field(description="Item description")
      quantity: int = Field(description="Quantity")
      unit_price: float = Field(description="Price per unit")
      amount: float = Field(description="Line total")

  class Invoice(BaseModel):
      # REQUIRED
      invoice_number: str = Field(description="Invoice number")
      total: float = Field(description="Total amount due")
      line_items: list[LineItem] = Field(description="Line items")
      
      # OPTIONAL
      vendor: Vendor | None = None
      subtotal: float | None = None
      tax: float | None = None

  result = client.extract(
      file="invoice.pdf",
      schema=Invoice,
      confidence_threshold=0.85
  )
  ```
</CodeGroup>

### Response with Line Items and Verification

```json theme={null}
{
  "object": {
    "invoice_number": "INV-2024-0042",
    "vendor": {
      "name": "Acme Corp",
      "address": "123 Business Ave, New York, NY 10001"
    },
    "line_items": [
      {
        "description": "Professional Services",
        "quantity": 10,
        "unit_price": 100.00,
        "amount": 1000.00
      },
      {
        "description": "Software License",
        "quantity": 1,
        "unit_price": 150.00,
        "amount": 150.00
      }
    ],
    "subtotal": 1150.00,
    "tax": 100.00,
    "total": 1250.00,
    "_meta": {
      "confidence_score": 0.95,
      "field_confidence": [
        { "field": "$.invoice_number", "score": 0.98, "reason": "Exact match", "page": 1, "text": "INV-2024-0042" },
        { "field": "$.total", "score": 0.96, "reason": "Exact match", "page": 1, "text": "Total: $1,250.00" },
        { "field": "$.line_items[0].description", "score": 0.94, "reason": "Exact match", "page": 1, "text": "Professional Services" }
      ],
      "issues": []
    }
  },
  "metadata": {
    "processing_time_ms": 3200,
    "credits": 1,
    "fallback_triggered": false
  },
  "verification": {
    "status": "PASSED",
    "checks_passed": 2,
    "checks_failed": 0,
    "cannot_verify_count": 0,
    "checks_run": [
      {
        "type": "HORIZONTAL_SUM",
        "status": "PASSED",
        "fields": ["total", "subtotal", "tax"],
        "passed": true,
        "delta": 0.0,
        "expected": 1250.00,
        "actual": 1250.00
      },
      {
        "type": "VERTICAL_SUM",
        "status": "PASSED",
        "fields": ["subtotal", "line_items"],
        "passed": true,
        "delta": 0.0,
        "expected": 1150.00,
        "actual": 1150.00
      }
    ]
  }
}
```

## Fallback Behavior

When a **required** field returns `null` or falls below `confidence_threshold`, the API automatically triggers the fallback model (Tier 2):

```json theme={null}
{
  "object": { ... },
  "metadata": {
    "processing_time_ms": 5500,
    "credits": 2,
    "fallback_triggered": true,
    "confidence_score": 0.97
  }
}
```

<Warning>
  The fallback model (Tier 2) consumes more credits. To avoid unexpected costs, mark fields as optional if they might be missing in >20% of your documents.
</Warning>

## Error Responses

### Invalid File Type (400)

```json theme={null}
{
  "detail": "Invalid file type. Supported formats: PDF, DOCX"
}
```

### Invalid Schema (400)

```json theme={null}
{
  "detail": "Invalid JSON schema: Expecting property name enclosed in double quotes"
}
```

### Unauthorized (401)

```json theme={null}
{
  "detail": "Invalid or missing API key"
}
```

### Rate Limited (429)

```json theme={null}
{
  "detail": "Rate limit exceeded. Please retry after 1 second."
}
```

### Extraction Failed (200 with error)

```json theme={null}
{
  "object": null,
  "metadata": {
    "processing_time_ms": 5000,
    "credits": 1,
    "fallback_triggered": true
  },
  "error": {
    "code": "EXTRACTION_FAILED",
    "message": "Unable to extract data from document"
  }
}
```

## Rate Limits

* **Request Rate**: 1 request per second per IP
* **File Size**: Maximum 10 MB

See [Rate Limits](/api-reference/rate-limits) for more details.
