# Get Batch Source: https://docs.matil.ai/api-reference/batches/get-batch /api-reference/openapi.json get /v3/batches/{batch_id} Get the current status and results of a batch processing request. Returns progress information (`total_items`, `completed_items`, `failed_items`), individual item results with their extracted data, and any failed webhook deliveries for debugging. # Process (async) Source: https://docs.matil.ai/api-reference/deployments/process-async /api-reference/openapi.json post /v3/deployments/{deployment_id}/async Send one or more documents for processing and receive the result later via webhook. Returns immediately with an `entry_id` and `status: "pending"`. When processing completes, Matil sends a POST request to your webhook URL with the result. ## Request body - `documents` (required): Array of document objects. - `webhook` (required): Object with `url` (your endpoint), `secret` (optional, for HMAC signature verification), and `incremental` (optional, defaults to `true`). - `metadata` (optional): Custom key-value object stored with the result. ## Webhook events - `structurer.completed`: Processing succeeded. Payload contains the extracted data. - `structurer.failed`: Processing failed. Payload contains error details. # Process (batch) Source: https://docs.matil.ai/api-reference/deployments/process-batch /api-reference/openapi.json post /v3/deployments/{deployment_id}/batch Submit multiple items for processing in a single request. Each item contains its own documents and optional metadata. Returns immediately with a `batch_id` and the total item count. Results are delivered via webhook as items complete. ## Request body - `requests` (required): Array of batch items (max 100). Each item has `documents` (required) and `metadata` (optional). - `webhook` (required): Object with `url`, `secret` (optional), and `incremental` (optional, defaults to `true`). When `incremental` is `true`, a webhook is sent as each item completes. When `false`, a single webhook is sent when the entire batch finishes. ## Webhook events - `batch.item.completed`: A single item finished processing (incremental mode). - `batch.completed`: The entire batch finished. - `batch.failed`: All items in the batch failed. # Process (sync) Source: https://docs.matil.ai/api-reference/deployments/process-sync /api-reference/openapi.json post /v3/deployments/{deployment_id} Send one or more documents for processing and wait for the result. The request blocks until processing completes and returns the extracted data directly in the response. ## Request body - `documents` (required): Array of document objects. Each document must have a `type` field (`url`, `base64`, or `text`). - `metadata` (optional): Custom key-value object stored with the result. ## Response fields - `entry_id`: Unique identifier for this result. - `resource_type`: Always `"structure"`. - `resource_id`: The structure used for extraction. - `resource_version_number`: The version of the structure applied. - `data`: The extracted data as structured JSON. - `errors`: Validation errors, if any. `null` when everything is correct. - `status`: `completed`, `completed_with_errors`, or `failed`. - `time_ms`: Processing time in milliseconds. - `price`: Cost of this request. # Create Entry Correction Source: https://docs.matil.ai/api-reference/entries/create-entry-correction /api-reference/openapi.json post /v3/entries/{entry_id}/correction Create or update a correction for an entry. Supports two correction modes: 1. **Full replacement**: Provide the complete corrected object in the `data` field. 2. **Path-based patches**: Provide a list of field-level patches, each with a JSON Pointer `path` and the new `value`. You can also include `notes` to describe the reason for the correction. # Get Entry Source: https://docs.matil.ai/api-reference/entries/get-entry /api-reference/openapi.json get /v3/entries/{entry_id} Retrieve a specific entry by ID. Returns the entry's extracted data, processing status, price, validation errors, and associated documents. # Authentication Source: https://docs.matil.ai/en/api-reference/authentication How to authenticate your requests to the Matil API. All requests require an API key in the `x-api-key` header: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} x-api-key: your-api-key ``` ## Getting your API key 1. Log in to the [Matil Dashboard](https://admin.matil.ai) 2. Go to **Settings > API Keys** 3. Click **Create New Key** and copy it immediately — it won't be shown again ## Example request ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -X POST "https://api.matil.ai/v3/deployments/{deployment_id}" \ -H "x-api-key: your-api-key" \ -H "Content-Type: application/json" \ -d '{"documents": [{"type": "url", "url": "https://example.com/invoice.pdf"}]}' ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} import os import requests response = requests.post( f"https://api.matil.ai/v3/deployments/{deployment_id}", headers={ "x-api-key": os.environ["MATIL_API_KEY"], "Content-Type": "application/json" }, json={"documents": [{"type": "url", "url": "https://example.com/invoice.pdf"}]} ) ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const response = await fetch( `https://api.matil.ai/v3/deployments/${deploymentId}`, { method: "POST", headers: { "x-api-key": process.env.MATIL_API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ documents: [{ type: "url", url: "https://example.com/invoice.pdf" }] }) } ); ``` Store your API key in an environment variable. Never hardcode it in source code or commit it to version control. # Document input Source: https://docs.matil.ai/en/api-reference/document-input How to format documents in your API requests. Every processing request includes a `documents` array. Each document must have a `type` field that determines how Matil receives the content. ## URL Send a direct download link. Matil fetches the file and processes it. ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "documents": [ { "type": "url", "url": "https://example.com/invoice.pdf" } ] } ``` The URL must point directly to the file. Links that require authentication, redirect to a login page, or return HTML instead of the file will fail with a `400` error. For services like Google Drive or Dropbox, use the direct download URL, not the sharing link. ## Base64 Send the file content encoded in base64. Always include `mime_type` so Matil knows how to process the file. ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "documents": [ { "type": "base64", "content": "JVBERi0xLjQKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZw...", "mime_type": "application/pdf", "filename": "invoice.pdf" } ] } ``` | Field | Required | Description | | ----------- | -------- | ------------------------------------------------------------------------------------- | | `content` | Yes | The base64-encoded file content. | | `mime_type` | No | MIME type of the file (e.g. `application/pdf`, `image/png`). Strongly recommended. | | `filename` | No | Original filename. Helps Matil detect the file type when `mime_type` is not provided. | Send only the raw base64 string. Do not include the `data:application/pdf;base64,` prefix — that is a Data URI format used in browsers, not in API requests. ### Encoding a file to base64 ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} import base64 with open("invoice.pdf", "rb") as f: content = base64.b64encode(f.read()).decode("utf-8") # Use in your request document = { "type": "base64", "content": content, "mime_type": "application/pdf", "filename": "invoice.pdf" } ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} import fs from "fs"; const content = fs.readFileSync("invoice.pdf").toString("base64"); // Use in your request const document = { type: "base64", content: content, mime_type: "application/pdf", filename: "invoice.pdf" }; ``` ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}} # Encode and send in one command curl -X POST "https://api.matil.ai/v3/deployments/{deployment_id}" \ -H "x-api-key: your-api-key" \ -H "Content-Type: application/json" \ -d "{ \"documents\": [{ \"type\": \"base64\", \"content\": \"$(base64 -i invoice.pdf)\", \"mime_type\": \"application/pdf\", \"filename\": \"invoice.pdf\" }] }" ``` ```csharp C# theme={"theme":{"light":"github-light","dark":"github-dark"}} byte[] bytes = File.ReadAllBytes("invoice.pdf"); string content = Convert.ToBase64String(bytes); var document = new { type = "base64", content = content, mime_type = "application/pdf", filename = "invoice.pdf" }; ``` ```java Java theme={"theme":{"light":"github-light","dark":"github-dark"}} import java.nio.file.Files; import java.nio.file.Path; import java.util.Base64; byte[] bytes = Files.readAllBytes(Path.of("invoice.pdf")); String content = Base64.getEncoder().encodeToString(bytes); ``` ## Text Send plain text directly. This is useful for passing additional instructions or context alongside other documents, or for processing text that you already have extracted. ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "documents": [ { "type": "url", "url": "https://example.com/invoice.pdf" }, { "type": "text", "text": "The invoice currency is USD. The supplier VAT ID is ES12345678A." } ] } ``` In this example, the first document is the actual file and the second provides extra context that helps Matil extract the data more accurately. ## Multiple documents You can send multiple documents in a single request. Matil processes them together as a single unit. ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "documents": [ { "type": "url", "url": "https://example.com/invoice-page1.pdf" }, { "type": "url", "url": "https://example.com/invoice-page2.pdf" } ] } ``` ## Per-document metadata Each document accepts an optional `metadata` object for your own tracking: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "documents": [ { "type": "url", "url": "https://example.com/invoice.pdf", "metadata": {"source": "email", "sender": "supplier@example.com"} } ] } ``` # Error handling Source: https://docs.matil.ai/en/api-reference/error-handling HTTP status codes and error response format. ## HTTP status codes | Status | Description | | ------ | --------------------------------------------------------------------------------- | | `200` | Success. | | `400` | Bad request — document download failed or invalid URL. | | `401` | Unauthorized — invalid or missing API key. | | `402` | Insufficient credits — top up your balance to continue. | | `404` | Not found — deployment, entry, or batch doesn't exist. | | `422` | Validation error — invalid request body or document format. | | `503` | Service temporarily unavailable due to high load. Retry with exponential backoff. | ## Error response format ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "error": "DEPLOYMENT_NOT_FOUND", "message": "Deployment not found", "details": null } ``` | Field | Type | Description | | --------- | -------------- | ---------------------------------- | | `error` | string | Machine-readable error code. | | `message` | string | Human-readable description. | | `details` | object or null | Additional context when available. | ## Processing errors vs. API errors * **API errors** (4xx): the request itself failed. No document was processed. * **Processing errors** (in the `errors` field of a `200` response): the document was processed but some fields couldn't be extracted or validated. A response with `status: "completed_with_errors"` is still a `200 OK`: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "data": {"invoice_number": "INV-001", "total": null}, "errors": [{"path": "/total", "message": "Required field missing", "code": "REQUIRED_FIELD"}], "status": "completed_with_errors" } ``` ## Retry strategy For `503` (high load) responses, implement exponential backoff: ```python theme={"theme":{"light":"github-light","dark":"github-dark"}} import time import requests def process_with_retry(deployment_id, documents, api_key, max_retries=3): for attempt in range(max_retries): response = requests.post( f"https://api.matil.ai/v3/deployments/{deployment_id}", headers={"x-api-key": api_key}, json={"documents": documents} ) if response.status_code == 503: time.sleep(2 ** attempt) continue return response.json() raise Exception("Max retries exceeded") ``` # Overview Source: https://docs.matil.ai/en/api-reference/overview Base URL, versioning, and response format for the Matil API. The Matil API lets you send documents and receive structured data back. All requests use the base URL: ``` https://api.matil.ai/v3 ``` ## Response format Processing endpoints return this structure: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "entry_id": "01934b1a-89ab-7def-0123-456789abcdef", "resource_type": "structure", "resource_id": "01934b1a-1234-7abc-0000-111122223333", "resource_version_number": 1, "data": { "invoice_number": "INV-2024-001", "date": "2024-01-15", "total": 150.00 }, "errors": null, "status": "completed", "time_ms": 2340, "price": 0.05 } ``` | Field | Type | Description | | ------------------------- | ------------- | -------------------------------------------------- | | `entry_id` | UUID | Unique identifier for this result. | | `resource_type` | string | Always `"structure"`. | | `resource_id` | UUID | The structure used for extraction. | | `resource_version_number` | integer | The version of the structure applied. | | `data` | object | The extracted data as structured JSON. | | `errors` | array or null | Validation errors, if any. | | `status` | string | `completed`, `completed_with_errors`, or `failed`. | | `time_ms` | integer | Processing time in milliseconds. | | `price` | float | Cost of this request. | ## Versioning The current API version is `v3`. All endpoints are prefixed with `/v3/`. We maintain backward compatibility within a version. # Processing modes Source: https://docs.matil.ai/en/api-reference/processing Synchronous, asynchronous, and batch processing. Matil offers three ways to process documents through a deployment. All three use the same document input format and return the same result structure. ## Synchronous The request blocks until processing completes. The result is returned directly in the response. ``` POST /v3/deployments/{deployment_id} ``` Use this when you need the result immediately and can wait for the response (typically 1-10 seconds). ## Asynchronous The request returns immediately with an `entry_id` and `status: "pending"`. The result is delivered to your webhook URL when ready. ``` POST /v3/deployments/{deployment_id}/async ``` Include a `webhook` object in the request body: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "documents": [{"type": "url", "url": "https://example.com/invoice.pdf"}], "webhook": { "url": "https://your-server.com/webhook", "secret": "your-webhook-secret" } } ``` Use this when you don't need the result immediately and want to decouple submission from result handling. ## Batch Submit up to 100 items in a single request. Returns a `batch_id` and total item count. Results are delivered via webhook. ``` POST /v3/deployments/{deployment_id}/batch ``` ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "requests": [ { "metadata": {"order_id": "ORD-001"}, "documents": [{"type": "url", "url": "https://example.com/invoice-1.pdf"}] }, { "metadata": {"order_id": "ORD-002"}, "documents": [{"type": "url", "url": "https://example.com/invoice-2.pdf"}] } ], "webhook": { "url": "https://your-server.com/webhook", "secret": "your-webhook-secret", "incremental": true } } ``` The `incremental` flag controls delivery: | Value | Behavior | | ------- | -------------------------------------------------------- | | `true` | A webhook is sent as each item completes. | | `false` | A single webhook is sent when the entire batch finishes. | Check batch progress at any time: ``` GET /v3/batches/{batch_id} ``` # Webhooks Source: https://docs.matil.ai/en/api-reference/webhooks Receive processing results via webhook. Async and batch requests deliver results to your webhook URL. Matil sends a `POST` request with the result payload when processing completes. ## Configuration Include a `webhook` object in your request: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "webhook": { "url": "https://your-server.com/webhook", "secret": "your-webhook-secret" } } ``` ## Signature verification Every webhook includes a `X-Matil-Signature` header: ``` X-Matil-Signature: t=1234567890,v1=abc123... ``` Verify it to ensure the request came from Matil: ```python theme={"theme":{"light":"github-light","dark":"github-dark"}} import hmac import hashlib import time def verify_webhook(payload: bytes, header: str, secret: str) -> bool: parts = dict(p.split("=", 1) for p in header.split(",")) timestamp = parts["t"] signature = parts["v1"] signed_payload = f"{timestamp}.{payload.decode()}" expected = hmac.new( secret.encode(), signed_payload.encode(), hashlib.sha256 ).hexdigest() if not hmac.compare_digest(signature, expected): return False if abs(time.time() - int(timestamp)) > 300: return False return True ``` Always verify webhook signatures. Without verification, anyone could send fake payloads to your endpoint. ## Retry behavior If your endpoint doesn't respond with a `2xx` status, Matil retries up to 3 times with exponential backoff. ## Events | Event | Trigger | | ---------------------- | ----------------------------------------- | | `structurer.completed` | Async processing succeeded. | | `structurer.failed` | Async processing failed. | | `batch.item.completed` | A batch item finished (incremental mode). | | `batch.completed` | The entire batch finished. | | `batch.failed` | The entire batch failed. | # Deployments Source: https://docs.matil.ai/en/guides/deployments A stable entry point to process documents — linking your API calls to a specific structure version. A **deployment** connects a structure to a stable ID that you use in API calls. Instead of passing configuration in every request, you point to a deployment and Matil knows exactly what to do. ## Why deployments? Deployments give you a layer of indirection that makes your integration more robust: * **Update without code changes.** Publish a new structure version and assign it to the deployment. Your API calls don't change. * **Separate environments.** Use different deployments for development, staging, and production — each pointing to the right structure version. * **Track history.** Every time you change which structure version a deployment uses, it's recorded. ## What's inside a deployment? | Component | Description | | ----------------- | --------------------------------------------------------------------- | | **Deployment ID** | A unique UUID you use in API calls. | | **Structure** | The structure (and version) that this deployment uses for processing. | | **Name** | A human-readable label for your reference. | Deployments are created and managed in the [Matil Dashboard](https://admin.matil.ai). The API is used to process documents through them. ## Using a deployment Once you have a deployment ID, processing a document is a single API call: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -X POST "https://api.matil.ai/v3/deployments/{deployment_id}" \ -H "x-api-key: your-api-key" \ -H "Content-Type: application/json" \ -d '{"documents": [{"type": "url", "url": "https://example.com/invoice.pdf"}]}' ``` The deployment determines which structure and version to apply. You also have async and batch variants: | Mode | Endpoint | Description | | --------- | --------------------------------- | --------------------------------------------------------------- | | **Sync** | `POST /v3/deployments/{id}` | Blocks until processing completes. Returns the result directly. | | **Async** | `POST /v3/deployments/{id}/async` | Returns immediately. Result delivered via webhook. | | **Batch** | `POST /v3/deployments/{id}/batch` | Submit up to 100 items. Results delivered via webhook. | ## Next steps Learn how to define what data you want to extract. Learn the details of sync, async, and batch processing. # Documents Source: https://docs.matil.ai/en/guides/documents How to send documents to Matil — URLs, base64, or plain text. Every processing request in Matil includes one or more documents. A document is the input you want to process — an invoice, a contract, an ID card, or any other file. Matil accepts documents in several formats, so you can integrate regardless of how your files are stored or received. ## Supported file types Matil can process a wide range of document formats: | Category | Formats | | ---------------- | --------------------------------------------------------- | | **PDF** | `.pdf` | | **Images** | `.jpg`, `.jpeg`, `.png`, `.gif`, `.webp`, `.tiff`, `.bmp` | | **Spreadsheets** | `.xlsx`, `.xls`, `.ods`, `.csv` | | **Text** | `.txt`, `.html`, `.xml`, `.json` | The maximum file size is **50 MB**. ## Input formats ### URL Point to a document hosted online. Matil downloads and processes it automatically. This is the most common way to send documents. ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "type": "url", "url": "https://example.com/invoice.pdf" } ``` ### Base64 encoded Send binary files directly in the request body. Useful when you have files in memory. ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "type": "base64", "content": "JVBERi0xLjQK...", "mime_type": "application/pdf" } ``` Here's how to encode a file in Python: ```python theme={"theme":{"light":"github-light","dark":"github-dark"}} import base64 with open("document.pdf", "rb") as f: encoded = base64.b64encode(f.read()).decode("utf-8") document = { "type": "base64", "content": encoded, "mime_type": "application/pdf" } ``` ### Plain text Send raw text content directly. Useful when you already have the text extracted. ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "type": "text", "text": "INVOICE\n\nInvoice Number: INV-2024-001\nDate: January 15, 2024\nTotal: $150.00" } ``` ## Multiple documents You can send multiple documents in a single request. Matil processes them together as a single unit — useful for multi-page documents that arrive as separate files. ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "documents": [ {"type": "url", "url": "https://example.com/page1.pdf"}, {"type": "url", "url": "https://example.com/page2.pdf"} ] } ``` ## Adding metadata You can attach custom metadata to any request. This metadata is stored with the result and returned in responses and webhooks — useful for correlating results with your system. ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "documents": [ {"type": "url", "url": "https://example.com/invoice.pdf"} ], "metadata": { "order_id": "ORD-12345", "source": "email-inbox", "customer_id": "cust_abc" } } ``` Use metadata to link Matil results back to records in your own database. This makes it easy to match processed entries with their source. ## Next steps Process many documents efficiently with batch mode. Learn how to extract structured data from your documents. # Entries Source: https://docs.matil.ai/en/guides/entries Every processed result is stored as an entry — retrieve, review, and correct them. Every time Matil processes a document, the result is stored as an **entry**. An entry contains the extracted data, any validation errors, processing metadata, and a unique ID. Entries are your record of what was extracted. You can retrieve them later, review the results, and submit corrections. ## What's in an entry? When you process a document synchronously, the response is: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "entry_id": "01934b1a-89ab-7def-0123-456789abcdef", "resource_type": "structure", "resource_id": "01934b1a-1234-7abc-0000-111122223333", "resource_version_number": 1, "data": { "invoice_number": "INV-2024-001", "date": "2024-01-15", "total": 1250.00 }, "errors": null, "status": "completed", "time_ms": 2340, "price": 0.05 } ``` | Field | Description | | ------------------------- | ------------------------------------------------------------- | | `entry_id` | Unique ID for this result. | | `resource_type` | Always `"structure"`. | | `resource_id` | The structure used for extraction. | | `resource_version_number` | The version of the structure applied. | | `data` | The extracted data as structured JSON. | | `errors` | Validation errors, if any. `null` when everything is correct. | | `status` | `completed`, `completed_with_errors`, or `failed`. | | `time_ms` | Processing time in milliseconds. | | `price` | Cost of this request. | ## Retrieving entries Fetch a specific entry by its ID: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl "https://api.matil.ai/v3/entries/{entry_id}" \ -H "x-api-key: your-api-key" ``` ## Corrections If the extracted data isn't quite right, you can submit a correction: ```bash theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -X POST "https://api.matil.ai/v3/entries/{entry_id}/correction" \ -H "x-api-key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "data": { "invoice_number": "INV-2024-001", "total": 1350.00 } }' ``` The response confirms how many patches were applied: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "entry_id": "01934b1a-89ab-7def-0123-456789abcdef", "patches_applied": 1 } ``` ## Next steps Define what data gets extracted into entries. Handle processing errors and edge cases. # Structures Source: https://docs.matil.ai/en/guides/structures Define the fields you want to extract from your documents. A **structure** is a schema that defines what data to extract from a document. You define the fields — name, type, description — and Matil reads the document and fills them in. Structures are the foundation of everything in Matil. Every deployment points to a structure. ## How it works 1. **Define a structure** in the [Matil Dashboard](https://admin.matil.ai). For example, an invoice structure might have fields like `invoice_number`, `invoice_date`, `total`, and `lines`. 2. **Publish a version.** Structures use a draft/publish workflow. Edit the draft, then publish when ready. 3. **Create a deployment** that points to that structure version. 4. **Send documents** via the API. Matil extracts the data and returns structured JSON. ## Example If your structure defines fields for an invoice, the extracted `data` in the response looks like: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "invoice_number": "INV-2024-001", "invoice_date": "2024-01-15", "currency": "EUR", "lines": [ { "description": "Consulting services", "quantity": 10, "unit_price": 125.00, "line_total": 1250.00 } ], "subtotal": 1250.00, "tax_amount": 262.50, "total": 1512.50 } ``` ## Pricing and pages Custom structures are billed at **0.10 € per page**. A "page" depends on the document type: | Document type | What counts as 1 page | | --------------- | -------------------------------------- | | **PDF** | 1 PDF page = 1 page | | **Image** | 1 image = 1 page | | **Text** | Every 200 words = 1 page (minimum 1) | | **Spreadsheet** | Every 1,500 cells = 1 page (minimum 1) | For example, a 3-page PDF costs 0.30 €. A spreadsheet with 4,500 cells counts as 3 pages (0.30 €). Marketplace structures have their own fixed price per page, shown on each structure's page in the [Marketplace](https://matil.ai/marketplace). ## Field types ### Data fields These are the fields that produce values in the output: | Type | Description | Output example | | ------------- | --------------------------------------------------------------------------- | ------------------------------------------ | | `text` | A single string value. Supports regex validation and allowed values (enum). | `"INV-2024-001"` | | `number` | A single numeric value. Supports decimal precision and rounding. | `1250.00` | | `boolean` | A true/false value. | `true` | | `list_text` | A list of strings. | `["EUR", "USD"]` | | `list_number` | A list of numbers. | `[10.0, 20.5]` | | `object` | A nested object with its own subfields. | `{"street": "...", "city": "..."}` | | `list_object` | A table — a list of rows, each with the same columns. | `[{"description": "...", "quantity": 10}]` | ### Structural fields These organize extraction but don't produce keys in the output: | Type | Description | | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `group` | Groups fields into an execution unit. Enables parallel extraction, conditional execution, and contextual instructions. Child fields are flattened to the parent namespace in the output. | | `structure` | References another structure's versioned definition. Its fields are flattened into the parent output. | | `validation` | An inline rule that verifies extracted data and can trigger automatic corrections or LLM retries. | ## Groups Groups let you organize fields into separate extraction units that can run **in parallel**, improving performance for complex structures. A structure with groups: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "fields": [ { "type": "group", "name": "header", "fields": [ { "type": "text", "name": "invoice_number", "description": "..." }, { "type": "text", "name": "currency", "description": "..." } ] }, { "type": "group", "name": "line_items", "instruction": "Extract line items. Currency is {/currency}.", "fields": [ { "type": "list_object", "name": "lines", "description": "...", "columns": [...] } ] } ] } ``` Produces a flat output — group names don't appear: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "invoice_number": "INV-001", "currency": "EUR", "lines": [...] } ``` Groups can also be **conditional** (skipped if an expression evaluates to false) and can include **instructions** with `{/path}` placeholders that reference data from other groups. ## Computed fields Any field can be marked as `is_computed: true`. Instead of being extracted by the LLM, its value is calculated from an expression after extraction. Useful for derived values like line totals. ## Validations Structures can include validation rules that verify extracted data. When a validation fails, it can trigger programmatic corrections (e.g., recalculate a field) or ask the LLM to re-extract specific fields. When a field fails validation, the response status is `completed_with_errors` and includes an `errors` array: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "errors": [ { "path": "/total", "message": "Required field missing", "code": "REQUIRED_FIELD" } ], "status": "completed_with_errors" } ``` | Status | Meaning | | ----------------------- | ----------------------------------------------------------------------------------- | | `completed` | All fields extracted and validated successfully. | | `completed_with_errors` | Extraction succeeded, but some fields failed validation. Partial data is available. | | `failed` | Processing could not complete. | ## Versioning Structures use a **draft/publish** workflow: * **Draft** — Your working copy. Edit freely without affecting live processing. * **Published version** — A snapshot that deployments can point to. Once published, a version is immutable. You can publish as many versions as you want. Each deployment chooses which version to use, so you can test a new version on a staging deployment before rolling it to production. ## Next steps Connect your structure to a deployment for API access. Understand how results are stored and how to correct them. # Introduction Source: https://docs.matil.ai/en/introduction Turn documents into reliable, structured data — without building fragile pipelines. Matil is a document intelligence platform. You send documents — invoices, contracts, IDs, delivery notes, utility bills — and Matil returns clean, structured JSON. No templates. No manual rules. No OCR pipelines to maintain. ## How it works A structure defines what data to extract from a document. You can import one from the marketplace or build your own. A deployment links your structure to a stable ID that you use in API calls. Update the structure version without changing your integration. Use the API to send documents to your deployment. You can send URLs, base64-encoded files, or plain text. Matil processes your documents and returns validated JSON. Every result is stored as an **entry** that you can retrieve or correct later. ## Two ways to get a structure ### Use a ready-made structure from the marketplace The [Matil Marketplace](https://matil.ai/marketplace) offers pre-built structures for common document types — invoices, delivery notes, IDs, utility bills, and more. Import one and start processing immediately. Marketplace structures have a fixed price per page that varies depending on the structure. ### Build your own custom structure If your use case isn't covered by the marketplace, create a custom structure in the [Matil Dashboard](https://admin.matil.ai). Define exactly the fields you need, with the types, validations, and logic that match your requirements. Custom structures are billed at **0.10 € per page**. Browse ready-made structures for common document types. Learn how to define a custom structure. ## Key concepts * **Structures** — A schema that defines the fields to extract from a document. [Learn more](/en/guides/structures) * **Deployments** — A stable entry point that links a structure version to an API endpoint. [Learn more](/en/guides/deployments) * **Entries** — Every processed result is stored as an entry. You can retrieve, review, or correct entries. [Learn more](/en/guides/entries) * **Documents** — The input you send to Matil. Supports URLs, base64, and plain text. [Learn more](/en/guides/documents) ## Where to start Make your first API call in minutes. Understand how to define what data you want to extract. Set up your API keys. Jump straight to the endpoint documentation. # Quickstart Source: https://docs.matil.ai/en/quickstart Make your first API call to Matil in under 5 minutes. This guide walks you through making your first document processing request. By the end, you'll have sent a document and received structured data back. ## What you need 1. A Matil account — [sign up here](https://admin.matil.ai) 2. An API key 3. A deployment ID Don't have these yet? Follow the steps below. ## Get your API key Log in to the [Matil Dashboard](https://admin.matil.ai) and go to **Settings > API Keys**. Click **Create New Key**. Give it a name that helps you identify its purpose (e.g., "Development" or "Production"). Copy your API key immediately — it won't be shown again. Store your API key in an environment variable. Never hardcode it in your source code or commit it to version control. ## Find your deployment ID Go to **Deployments** in the dashboard. Select the deployment you want to use and copy its ID. A deployment ID is a UUID like: `01234567-89ab-cdef-0123-456789abcdef` If you don't have a deployment yet, create one in the dashboard first. A deployment defines what data you want to extract and from which type of document. ## Make your first request Send a document to your deployment: ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark"}} curl -X POST "https://api.matil.ai/v3/deployments/{your-deployment-id}" \ -H "x-api-key: your-api-key" \ -H "Content-Type: application/json" \ -d '{ "documents": [ { "type": "url", "url": "https://example.com/invoice.pdf" } ] }' ``` ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}} import requests API_KEY = "your-api-key" DEPLOYMENT_ID = "your-deployment-id" response = requests.post( f"https://api.matil.ai/v3/deployments/{DEPLOYMENT_ID}", headers={ "x-api-key": API_KEY, "Content-Type": "application/json" }, json={ "documents": [ { "type": "url", "url": "https://example.com/invoice.pdf" } ] } ) result = response.json() print(f"Entry ID: {result['entry_id']}") print(f"Status: {result['status']}") print(f"Extracted Data: {result['data']}") ``` ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}} const API_KEY = "your-api-key"; const DEPLOYMENT_ID = "your-deployment-id"; const response = await fetch( `https://api.matil.ai/v3/deployments/${DEPLOYMENT_ID}`, { method: "POST", headers: { "x-api-key": API_KEY, "Content-Type": "application/json" }, body: JSON.stringify({ documents: [ { type: "url", url: "https://example.com/invoice.pdf" } ] }) } ); const result = await response.json(); console.log("Entry ID:", result.entry_id); console.log("Status:", result.status); console.log("Extracted Data:", result.data); ``` ## Understand the response A successful response looks like this: ```json theme={"theme":{"light":"github-light","dark":"github-dark"}} { "entry_id": "01934b1a-89ab-7def-0123-456789abcdef", "resource_type": "structure", "resource_id": "01934b1a-1234-7abc-0000-111122223333", "resource_version_number": 1, "data": { "invoice_number": "INV-2024-001", "date": "2024-01-15", "total": 150.00 }, "errors": null, "status": "completed", "time_ms": 2340, "price": 0.05 } ``` | Field | Description | | ------------------------- | ------------------------------------------------------------------------- | | `entry_id` | Unique ID for this result. Use it to retrieve or correct the entry later. | | `resource_type` | Always `"structure"`. | | `resource_id` | The structure used for extraction. | | `resource_version_number` | The version of the structure that was applied. | | `data` | The extracted data, structured as JSON. | | `errors` | Validation errors, if any. `null` when everything is correct. | | `status` | `completed`, `completed_with_errors`, or `failed`. | | `time_ms` | How long processing took, in milliseconds. | | `price` | Cost of this request. | ## What's next? Understand how deployments connect structures to API calls. Learn about all the ways you can send documents to Matil. Sync, async, and batch processing explained. Handle errors gracefully in your integration.