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

# Form Fields

> Find the fillable fields on every page of a PDF or image: blank lines, empty boxes, tick boxes and signature blanks, with their types, locations and printed labels.

The form fields API reads a PDF or an image and returns every place a person has to fill something in. Each field comes with its type, its box on the page and the printed label next to it. Use it to inspect a form before you [fill it](https://documentation.datalab.to/docs/recipes/form-filling/form-filling-api-overview.md), to build a form from a scan, or to place signature and date blanks.

**Before you begin**, make sure you have:

1. A [Datalab account](https://www.datalab.to/auth/sign_up) with an [API key](https://www.datalab.to/app/keys)
2. Python 3.11+ installed
3. The Datalab SDK: `pip install datalab-python-sdk`
4. Your `DATALAB_API_KEY` environment variable set

## Quick Start

```python Python SDK theme={null}
from datalab_sdk import DatalabClient

client = DatalabClient()

result = client.form_fields("form.pdf")

for page in result.pages:
    for field in page["fields"]:
        print(page["page"], field["field_type"], field["bbox"], field["label"])
```

```bash cURL theme={null}
curl -X POST https://www.datalab.to/api/v1/form-fields \
  -H "X-API-Key: $DATALAB_API_KEY" \
  -F "file=@form.pdf"

# Poll request_check_url from the response until status is "complete"
```

```python Python (requests) theme={null}
import requests, time, os

headers = {"X-API-Key": os.getenv("DATALAB_API_KEY")}

with open("form.pdf", "rb") as f:
    response = requests.post(
        "https://www.datalab.to/api/v1/form-fields",
        files={"file": ("form.pdf", f, "application/pdf")},
        headers=headers,
    )

check_url = response.json()["request_check_url"]
for _ in range(300):
    data = requests.get(check_url, headers=headers).json()
    if data["status"] == "complete":
        break
    time.sleep(2)

for page in data["pages"]:
    for field in page["fields"]:
        print(page["page"], field["field_type"], field["bbox"], field["label"])
```

> [!WARNING]
>
> **Rate limits apply.** The default rate limit is 200 requests per minute (429 on exceed, SDK retries automatically). A separate [page concurrency limit](https://documentation.datalab.to/docs/common/limits.md#page-concurrency-limit) of 5,000 concurrent pages is enforced during processing — results return with `success: false` if exceeded. See [API Limits](https://documentation.datalab.to/docs/common/limits.md) for details.

## What a field looks like

```json theme={null}
{
  "status": "complete",
  "success": true,
  "page_count": 1,
  "pages": [
    {
      "page": 0,
      "error": "",
      "fields": [
        {"field_type": "name", "bbox": [0.094, 0.143, 0.941, 0.166], "label": "Name of entity/individual"},
        {"field_type": "checkbox", "bbox": [0.523, 0.085, 0.534, 0.095], "label": "Individual/sole proprietor"},
        {"field_type": "signature", "bbox": [0.18, 0.88, 0.62, 0.91], "label": "Signature"}
      ]
    }
  ]
}
```

| Field | Description |
| - | - |
| `page` | Page index, starting at 0 |
| `fields[].field_type` | The kind of field. See [field types](#field-types). |
| `fields[].bbox` | `[x0, y0, x1, y1]` as fractions of the page width and height. The origin is the top-left corner of the page. |
| `fields[].label` | The printed label that tells a person what belongs in the field. It is an empty string when the model gives no label. |
| `error` | Set when the model could not read the page, or repeated itself and its fields may be incomplete |

Fields come in the order the model reads the page. To get pixel coordinates, multiply `x0` and `x1` by the page width and `y0` and `y1` by the page height.

### Field types

`field_type` is one of: `signature`, `initials`, `email`, `name`, `firstName`, `lastName`, `company`, `title`, `date`, `text`, `checkbox`, `radio`.

A field is the empty space a person writes in. The API does not return printed labels, headings or instructions as fields, and it returns no field for a page that has none. A field with no rule or box, such as a blank inside a sentence, still counts.

## Options

| Parameter | Type | Default | Description |
| - | - | - | - |
| `file` / `file_url` | file / string | Required | A PDF or an image. Send one of the two. |
| `page_range` | string | All pages | Pages to process, for example `0,5-10,20`. |
| `max_pages` | integer | None | Process only the first pages. Do not combine it with `page_range`. |
| `skip_cache` | boolean | `false` | Run the detection again instead of returning a cached result. |
| `webhook_url` | string | None | URL that receives a call when the request completes. |
| `processing_location` | string | None | Residency region, for example `eu`, so page images stay in that region. |

> [!NOTE]
>
> Spreadsheets are not accepted. Send a PDF or an image.

> [!TIP]
>
> The first request after a period without traffic can take longer than later ones. Pages with many fields also take longer.

## Fill the fields you found

Detection tells you where the fields are. To write values into them, send the same file to the [form filling API](https://documentation.datalab.to/docs/recipes/form-filling/form-filling-api-overview.md) with your field data.

## Next Steps

> [card] [Form Fields SDK](https://documentation.datalab.to/docs/welcome/sdk/form-fields.md)
>
> Use form\_fields() from the Python SDK and the CLI.

> [card] [Form Filling](https://documentation.datalab.to/docs/recipes/form-filling/form-filling-api-overview.md)
>
> Fill the fields with structured data.

> [card] [API Reference](https://documentation.datalab.to/api-reference/health.md)
>
> See every parameter of the form fields endpoint.

> [card] [Pricing](https://www.datalab.to/pricing)
>
> Per-page pricing for form field detection.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.