Limai Docs
API ReferenceDocument Processing

Process File (Sync)

Extract structured data from an uploaded document synchronously.

POST/api/v1/document/{extractionSchemaId}/process-file/{fileId}SYNC

Extract structured data from an uploaded file using AI-powered document processing. This endpoint processes the document synchronously and returns the extracted data immediately upon completion.

Validations run as part of the call: the model's validation rules and the first pass of custom checks complete inline, so their pass/fail is already in the response. A failing check that is configured to RESEND (re-derive the value) does not block the response — that step continues asynchronously (see Validations). You get the first-round signal immediately and read the corrected outcome later.

For large files or batch processing, consider using the async endpoint instead.

Parameters

NameTypeInRequiredDescription
extractionSchemaIdstringpathYesThe model's ID, the ID of a deployment that points at it, or the model's extraction schema ID. The extraction schema ID is returned when listing a project's deployments, and is also shown at the bottom of the data page in the dashboard.
fileIdstringpathYesThe file ID returned from the get-url endpoint after uploading.

Body parameters

Every body parameter is optional. An empty JSON object {} is a valid body. Note that it does not guarantee a clean run: if this file was extracted before with overrides, they are stored on its job and are applied again when you send none. See Extraction Overrides.

NameTypeInRequiredDescription
columnDescriptionsobjectbodyNoReplacement extraction instructions for this run, keyed by column ID.
tableInstructionsobjectbodyNoReplacement table instructions for this run, keyed by table ID.
columnsOverrideobject[]bodyNoValues you supply yourself. Each array item is a single-key object mapping one column ID to its value; the column is then not extracted.

These are per-request overrides: they change this extraction without editing the model's schema, and they persist on the document's job for later re-runs. See Extraction Overrides for shapes, precedence, and limits.

Request

const response = await fetch(
`https://app.limai.io/api/v1/document/${SCHEMA_ID}/process-file/${fileId}`,
{
  method: "POST",
  headers: {
    "Authorization": `Bearer ${API_TOKEN}`,
    "Content-Type": "application/json"
  },
  body: JSON.stringify({})
}
)
const result = await response.json()

Response

The response carries the extracted data plus a file-level validations object, and every cell includes a validations array (empty when no check applies). The values reflect the first pass. In the example below the amount failed a RESEND reconciliation check: the check reports FAILED with behavior: "RESEND", and the re-derivation continues asynchronously — poll Get File Data (or listen for the DOCUMENT_VALIDATED webhook) to see it settle to RESEND_PASSED and the corrected, amended value.

Response200
{
  "message": "File processed successfully.",
  "fileId": "file_abc123def456",
  "jobId": "job_789xyz012",
  "data": {
    "tables": {
      "table_id_1": {
        "id": "table_id_1",
        "name": "Invoices",
        "slug": "invoices",
        "columns": [
          {
            "id": "col_1",
            "name": "Invoice Number",
            "type": "TEXT",
            "description": "Unique invoice identifier",
            "sharedColumnId": null,
            "slug": "invoice_number"
          },
          {
            "id": "col_2",
            "name": "Amount",
            "type": "NUMBER",
            "description": "Invoice total amount",
            "sharedColumnId": null,
            "slug": "amount"
          }
        ],
        "rows": [
          {
            "id": "row_1",
            "index": "0",
            "status": "PENDING",
            "cells": {
              "Invoice Number": {
                "value": "INV-001",
                "columnId": "col_1",
                "metadata": {
                  "id": "col_1",
                  "type": "TEXT",
                  "description": "Unique invoice identifier",
                  "slug": "invoice_number"
                },
                "validations": [
                  {
                    "checkKey": "vrule_2a8",
                    "source": "RULE",
                    "passed": true,
                    "message": null,
                    "expected": "non-empty value",
                    "actual": "INV-001",
                    "name": "Invoice Number is not empty",
                    "scope": "FIELD",
                    "operator": "IS_NOT_EMPTY",
                    "amended": false,
                    "previousValue": null,
                    "amendedValue": null
                  }
                ]
              },
              "Amount": {
                "value": "1000.00",
                "columnId": "col_2",
                "metadata": {
                  "id": "col_2",
                  "type": "NUMBER",
                  "description": "Invoice total amount",
                  "slug": "amount"
                },
                "validations": [
                  {
                    "checkKey": "amount-reconciliation",
                    "source": "SCRIPT",
                    "passed": false,
                    "message": "Amount does not reconcile with line items",
                    "expected": null,
                    "actual": null,
                    "name": null,
                    "scope": null,
                    "operator": null,
                    "amended": false,
                    "previousValue": null,
                    "amendedValue": null
                  }
                ]
              }
            }
          }
        ]
      }
    }
  },
  "validations": {
    "status": "failed",
    "failCount": 1,
    "checks": [
      {
        "key": "amount-reconciliation",
        "name": "Amount reconciliation",
        "source": "STATIC",
        "status": "FAILED",
        "behavior": "RESEND",
        "findings": [],
        "errorMessage": null,
        "startedAt": "2026-07-21T10:00:00.000Z",
        "completedAt": "2026-07-21T10:00:04.000Z"
      }
    ],
    "rules": {
      "crossField": [],
      "row": [],
      "document": []
    }
  },
  "modelId": "dep_abc123",
  "viaDeploymentId": "dpl_prod01",
  "schemaVersionId": "sv_7"
}

Beside the data, the envelope records how the run was addressed: modelId is the model the request resolved to, viaDeploymentId the deployment it arrived through (null when the request named the model directly), and schemaVersionId the schema version the run resolved to (null when the deployment tracks the draft).

Data Structure

Table

FieldTypeDescription
idstringUnique table identifier
namestringHuman-readable table name
columnsarrayArray of column definitions (id, name, type, description)
rowsarrayArray of extracted data rows

Row

FieldTypeDescription
idstringUnique row identifier
indexstringRow position
statusstringRow status: PENDING, ACCEPTED, or REJECTED
cellsobjectCell data keyed by column name
childTablesobjectNested child tables (if schema has relationships)

Cell

FieldTypeDescription
valuestringExtracted cell value
columnIdstringReference to the column definition
metadataobjectColumn metadata: id, type, description, and slug
validationsarrayPer-cell validation entries (see Validations). Empty when no check touched the cell

Validations

Validation runs before the response returns, but only the parts that are fast run inline:

  • Validation rules — the declarative checks configured on the model. They evaluate on the first pass, never re-extract, and cost nothing. See Validations.
  • Scripts and agents, first pass — custom checks run once against the extracted values. Their PASSED / FAILED result is in the response.
  • RESEND (asynchronous) — when a custom check fails and is configured to RESEND, re-deriving the value requires a fresh model call, so it is not done inline. The response reports that check as FAILED for now, and the re-derivation continues in the background.

To read the final outcome of a RESEND check, poll Get File Data with include=validations or listen for the DOCUMENT_VALIDATED webhook. Once it settles, the check reports RESEND_PASSED (corrected) or RESEND_FAILED (still failing), and any corrected cell is flagged amended: true.

Validation fields

Each per-cell entry in validations has:

FieldTypeDescription
checkKeystring | nullThe rule's id for RULE entries, the script's key for SCRIPT and AGENT entries
sourcestringRULE, SCRIPT, or AGENT
passedbooleanWhether the check passed for this cell
messagestring | nullFor rules, the composed failure detail, null when the rule passed. For scripts and agents, the finding's own message
expected / actualstring | nullCompared values, when the check reports them
namestring | nullThe rule's name or generated label. null for SCRIPT and AGENT entries, whose name is on the matching checks[] entry
scopestring | nullFIELD or COLUMN for a rule evaluated on this cell; null for custom checks
operatorstring | nullThe rule's operator; null for custom checks
amendedbooleantrue once a RESEND check has corrected this cell's value. Always false on the first-pass response and for RULE entries
previousValue / amendedValueany | nullThe value before and after a RESEND correction. null unless amended is true

The file-level validations object summarizes the run:

FieldTypeDescription
statusstring | nullThe document's validation status at the moment the response is built, across rules and custom checks
failCountnumber | nullNumber of failing checks, rules included; null when nothing has been evaluated
checksarrayPer-check results: key, name, source, behavior (SURFACE or RESEND), status, and timing
rulesobject | nullCross-field, row and document rule results grouped by scope, each entry carrying ruleId, passed, name, scope, operator, message and its compared values. Field and column rule results are on the cells instead

A check's status follows the lifecycle: PASSED / FAILED on the first pass (what this endpoint returns), then RESEND_PASSED / RESEND_FAILED once a RESEND check finishes re-extracting. RESEND_PASSED is the signal that a value initially failed and was corrected.

Error Responses

A paused deployment takes no new extraction work:

Response409
{
  "error": "Deployment dpl_prod01 on model dep_abc123 is PAUSED. Resume it before processing documents through it.",
  "code": "DEPLOYMENT_PAUSED",
  "deploymentId": "dpl_prod01",
  "modelId": "dep_abc123",
  "status": "PAUSED"
}

The same request addressed to the model, or through another active deployment on it, is unaffected.

When to Use Sync vs Async

SynchronousAsynchronous
Best forSmall files (< 10MB), real-time UIsLarge files, batch processing
BehaviorBlocks until completeReturns job ID immediately
Timeout riskMay timeout on large filesNo timeout limitations

The synchronous call waits for extraction and the first validation pass; RESEND re-extraction never blocks it, since that runs in the background either way. This response carries the same validation shape Get File Data returns, so an async run reaches the same data — including any RESEND outcome — on a later poll. The flat Document Data endpoint carries the same results in its own flat shape.

On this page