# Templates & Fields API Reference

> Create and manage extraction Templates and their Fields (the columns extraction produces), browse built-in preset templates, and control output field order for the ImageToTable.ai v1 API.

A **Template** is a saved, reusable list of **Fields** you want extracted from a document — one field per output column. Pass a Template's `id` to [Start processing a batch](/developers/reference/batches#start-processing-a-batch) instead of re-listing your fields on every call. You can also build a Template from a built-in [preset](#list-presets), or skip Templates entirely and pass ad-hoc `fields` directly to `process` for a one-off run.

## List templates

Returns your saved templates, each with its full, ordered field list embedded.

`GET /api/v1/templates`

### Parameters

| Name | Location | Type | Description |
| --- | --- | --- | --- |
| limit | query, optional | integer | 1–100. Default 50. |
| page_token | query, optional | string | Opaque cursor from a previous response's next_page_token . See Pagination . |

### Possible errors

- `missing_api_key` / `invalid_api_key` / `plan_required` — see [Error Handling](/developers/guides/errors).
- `invalid_parameter` — bad `limit` or `page_token`.

## Create a template

Two ways to create a template in one endpoint: from scratch (optionally cloning another template's fields via `base_template_id`), or from a built-in preset via `preset_id`.

`POST /api/v1/templates`

### Parameters

| Name | Location | Type | Description |
| --- | --- | --- | --- |
| name | body (JSON) | string | Required unless preset_id is given (in which case it falls back to the preset's own name, disambiguated with a timestamp suffix if you already have a template with that name). |
| preset_id | body (JSON) | string, optional | Build the template (and its fields) from a built-in preset — see List presets for valid IDs. |
| base_template_id | body (JSON) | integer, optional | Only used when preset_id is not given — clones this existing template's fields into the new one. |

### Possible errors

- `missing_api_key` / `invalid_api_key` / `plan_required` — see [Error Handling](/developers/guides/errors).
- `missing_parameter` (`param: "name"`) — no `name` and no `preset_id`.
- `invalid_parameter` (`param: "name"`) — a template with this name already exists (non-preset creation path only).
- `invalid_parameter` (`param: "preset_id"`) — unknown preset ID.
- `internal_error`

## Delete a template

Deletes a template and all of its fields (cascades — no separate cleanup call needed). Does not affect documents that already used this template in a past `process` call; their already-extracted results are untouched.

`DELETE /api/v1/templates/{id}`

### Parameters

| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | integer | The template to delete. |

### Possible errors

- `missing_api_key` / `invalid_api_key` / `plan_required` — see [Error Handling](/developers/guides/errors).
- `template_not_found`
- `internal_error`

## List presets

Built-in field lists for common document types (invoices, receipts, bank statements, and more) — pass a preset's `id` as `preset_id` to [Create a template](#create-a-template) to get a working template without hand-listing fields yourself. Presets are static configuration, not database rows — there's no way to create, edit, or delete one through the API.

`GET /api/v1/presets`

### Parameters

| Name | Location | Type | Description |
| --- | --- | --- | --- |
| category | query, optional | string | Filter to one category (e.g. "Finance & Accounting" ). Omit to list all categories. |
| limit | query, optional | integer | 1–100. Default 50. |
| page_token | query, optional | string | Opaque cursor from a previous response's next_page_token . |

### Possible errors

- `missing_api_key` / `invalid_api_key` / `plan_required` — see [Error Handling](/developers/guides/errors).
- `invalid_parameter` — bad `limit` or `page_token`.

## List and create fields

`fields` is the v1-public name for what the product UI calls "match rules" — one field per output column, in the order extraction will emit them. `GET` returns every field on the template, already sorted by `sort_order`. `POST` adds a new field to the end.

`GET POST /api/v1/templates/{id}/fields`

### Parameters

| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | integer | The template these fields belong to. |
| name | body (JSON), POST only | string | Required. Must be unique within this template — see errors below. |
| format_requirement | body (JSON), POST only | string, optional | Free-text hint about the expected value format (e.g. "YYYY-MM-DD" , "Number" ). |

### Possible errors

- `missing_api_key` / `invalid_api_key` / `plan_required` — see [Error Handling](/developers/guides/errors).
- `template_not_found`
- `missing_parameter` (`param: "name"`) — POST only.
- `duplicate_field_name` — a field with this `name` already exists on this template.
- `internal_error`

## Update and delete a field

`PUT` renames a field (and replaces its `format_requirement`) — it's a full replace, not a partial patch, so include both values even if only one changed. `DELETE` removes it.

`PUT DELETE /api/v1/templates/{id}/fields/{field_id}`

### Parameters

| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | integer | The template this field belongs to. |
| field_id | path | integer | The field to update or delete. |
| name | body (JSON), PUT only | string | Required. New name. |
| format_requirement | body (JSON), PUT only | string, optional | New format hint — omit and it's cleared to an empty string, not left unchanged. |

### Possible errors

- `missing_api_key` / `invalid_api_key` / `plan_required` — see [Error Handling](/developers/guides/errors).
- `template_not_found` — the template doesn't exist/isn't yours, or (with a message noting this) the `field_id` isn't on this template.
- `missing_parameter` (`param: "name"`) — PUT only.
- `duplicate_field_name` — PUT only, renaming to a name another field on this template already has.
- `internal_error`

## Reorder fields

Explicitly sets field order, which determines output column order in `line_items` and in Excel/Word exports. IDs in the list that don't belong to this template are silently ignored rather than rejecting the whole request.

`PATCH /api/v1/templates/{id}/fields/order`

### Parameters

| Name | Location | Type | Description |
| --- | --- | --- | --- |
| id | path | integer | The template to reorder. |
| field_ids | body (JSON) | array of integers | Every field ID on this template, in the order you want them to appear. Required. |

### Possible errors

- `missing_api_key` / `invalid_api_key` / `plan_required` — see [Error Handling](/developers/guides/errors).
- `template_not_found`
- `invalid_parameter` (`param: "field_ids"`) — not a list of integers.
- `internal_error`

## Code Examples

### List templates

GET /api/v1/templates

**cURL**

```bash
curl https://imagetotable.ai/api/v1/templates \
  -H "Authorization: Bearer $API_KEY"
```

**Python**

```python
import os
import requests

response = requests.get(
    "https://imagetotable.ai/api/v1/templates",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
)
print(response.json())
```

**Javascript**

```javascript
const response = await fetch("https://imagetotable.ai/api/v1/templates", {
  headers: { "Authorization": `Bearer ${process.env.API_KEY}` },
});
console.log(await response.json());
```

### Response

```json
{
  "data": [
    {
      "id": 42,
      "name": "Invoice Template",
      "created_at": "2026-06-01T10:00:00+00:00",
      "fields": [
        {
          "id": 101,
          "name": "invoice_number",
          "format_requirement": "",
          "sort_order": 1,
          "template_id": 42,
          "created_at": "2026-06-01T10:00:00+00:00"
        },
        {
          "id": 102,
          "name": "invoice_date",
          "format_requirement": "YYYY-MM-DD",
          "sort_order": 2,
          "template_id": 42,
          "created_at": "2026-06-01T10:00:00+00:00"
        }
      ]
    }
  ],
  "has_more": false,
  "next_page_token": null
}
```

### Create a template — from scratch

POST /api/v1/templates

The first of the two ways — just a `name`, no fields yet. Add fields afterward with [List and create fields](#list-and-create-fields), or clone another template's fields in the same call via `base_template_id`.

**cURL**

```bash
curl -X POST https://imagetotable.ai/api/v1/templates \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "My Invoice Template"}'
```

**Python**

```python
import os
import requests

response = requests.post(
    "https://imagetotable.ai/api/v1/templates",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={"name": "My Invoice Template"},
)
print(response.json())
```

**Javascript**

```javascript
const response = await fetch("https://imagetotable.ai/api/v1/templates", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "My Invoice Template" }),
});
console.log(await response.json());
```

### Response

```json
{
  "template": {
    "id": 44,
    "name": "My Invoice Template",
    "created_at": "2026-07-16T09:00:00+00:00",
    "fields": []
  }
}
```

### Create a template — from a preset

POST /api/v1/templates

**cURL**

```bash
curl -X POST https://imagetotable.ai/api/v1/templates \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"preset_id": "finance_invoice_general"}'
```

**Python**

```python
import os
import requests

response = requests.post(
    "https://imagetotable.ai/api/v1/templates",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={"preset_id": "finance_invoice_general"},
)
print(response.json())
```

**Javascript**

```javascript
const response = await fetch("https://imagetotable.ai/api/v1/templates", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ preset_id: "finance_invoice_general" }),
});
console.log(await response.json());
```

### Response

```json
{
  "template": {
    "id": 43,
    "name": "Invoice",
    "created_at": "2026-07-16T09:00:00+00:00",
    "fields": [
      {
        "id": 201,
        "name": "Merchant Name",
        "format_requirement": "String",
        "sort_order": 1,
        "template_id": 43,
        "created_at": "2026-07-16T09:00:00+00:00"
      }
    ]
  }
}
```

### Delete a template

DELETE /api/v1/templates/{id}

**cURL**

```bash
curl -X DELETE https://imagetotable.ai/api/v1/templates/43 \
  -H "Authorization: Bearer $API_KEY"
```

**Python**

```python
import os
import requests

response = requests.delete(
    "https://imagetotable.ai/api/v1/templates/43",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
)
print(response.status_code)
```

**Javascript**

```javascript
const response = await fetch("https://imagetotable.ai/api/v1/templates/43", {
  method: "DELETE",
  headers: { "Authorization": `Bearer ${process.env.API_KEY}` },
});
console.log(response.status);
```

### Response

204 No Content — empty body.

### List presets

GET /api/v1/presets

**cURL**

```bash
curl "https://imagetotable.ai/api/v1/presets?category=Finance%20%26%20Accounting" \
  -H "Authorization: Bearer $API_KEY"
```

**Python**

```python
import os
import requests

response = requests.get(
    "https://imagetotable.ai/api/v1/presets",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    params={"category": "Finance & Accounting"},
)
print(response.json())
```

**Javascript**

```javascript
const url = new URL("https://imagetotable.ai/api/v1/presets");
url.searchParams.set("category", "Finance & Accounting");

const response = await fetch(url, {
  headers: { "Authorization": `Bearer ${process.env.API_KEY}` },
});
console.log(await response.json());
```

### Response

```json
{
  "data": [
    {
      "id": "finance_invoice_general",
      "category": "Finance & Accounting",
      "name": "Invoice",
      "fields": [
        {"name": "Invoice Number", "format_requirement": "DocumentNumber"},
        {"name": "Invoice Date", "format_requirement": "YYYY-MM-DD"},
        {"name": "Total Amount", "format_requirement": "Number"}
      ]
    }
  ],
  "has_more": false,
  "next_page_token": null
}
```

### List / create fields

POST /api/v1/templates/{id}/fields

**cURL**

```bash
curl -X POST https://imagetotable.ai/api/v1/templates/42/fields \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "vendor_name", "format_requirement": "String"}'
```

**Python**

```python
import os
import requests

response = requests.post(
    "https://imagetotable.ai/api/v1/templates/42/fields",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={"name": "vendor_name", "format_requirement": "String"},
)
print(response.json())
```

**Javascript**

```javascript
const response = await fetch("https://imagetotable.ai/api/v1/templates/42/fields", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "vendor_name", format_requirement: "String" }),
});
console.log(await response.json());
```

### Response

```json
{
  "field": {
    "id": 103,
    "name": "vendor_name",
    "format_requirement": "String",
    "sort_order": 103,
    "template_id": 42,
    "created_at": "2026-07-16T09:05:00+00:00"
  }
}
```

### Update a field

PUT /api/v1/templates/{id}/fields/{field_id}

**cURL**

```bash
curl -X PUT https://imagetotable.ai/api/v1/templates/42/fields/103 \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "vendor_name", "format_requirement": "Company name, no suffix"}'
```

**Python**

```python
import os
import requests

response = requests.put(
    "https://imagetotable.ai/api/v1/templates/42/fields/103",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={"name": "vendor_name", "format_requirement": "Company name, no suffix"},
)
print(response.json())
```

**Javascript**

```javascript
const response = await fetch("https://imagetotable.ai/api/v1/templates/42/fields/103", {
  method: "PUT",
  headers: {
    "Authorization": `Bearer ${process.env.API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ name: "vendor_name", format_requirement: "Company name, no suffix" }),
});
console.log(await response.json());
```

### Response

```json
{
  "field": {
    "id": 103,
    "name": "vendor_name",
    "format_requirement": "Company name, no suffix",
    "sort_order": 103,
    "template_id": 42,
    "created_at": "2026-07-16T09:05:00+00:00"
  }
}
```

### Delete a field

DELETE /api/v1/templates/{id}/fields/{field_id}

**cURL**

```bash
curl -X DELETE https://imagetotable.ai/api/v1/templates/42/fields/103 \
  -H "Authorization: Bearer $API_KEY"
```

**Python**

```python
import os
import requests

response = requests.delete(
    "https://imagetotable.ai/api/v1/templates/42/fields/103",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
)
print(response.status_code)
```

**Javascript**

```javascript
const response = await fetch("https://imagetotable.ai/api/v1/templates/42/fields/103", {
  method: "DELETE",
  headers: { "Authorization": `Bearer ${process.env.API_KEY}` },
});
console.log(response.status);
```

### Response

204 No Content — empty body.

### Reorder fields

PATCH /api/v1/templates/{id}/fields/order

**cURL**

```bash
curl -X PATCH https://imagetotable.ai/api/v1/templates/42/fields/order \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"field_ids": [102, 101, 103]}'
```

**Python**

```python
import os
import requests

response = requests.patch(
    "https://imagetotable.ai/api/v1/templates/42/fields/order",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    json={"field_ids": [102, 101, 103]},
)
print(response.json())
```

**Javascript**

```javascript
const response = await fetch("https://imagetotable.ai/api/v1/templates/42/fields/order", {
  method: "PATCH",
  headers: {
    "Authorization": `Bearer ${process.env.API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({ field_ids: [102, 101, 103] }),
});
console.log(await response.json());
```

### Response

```json
{
  "data": [
    {"id": 102, "name": "invoice_date", "format_requirement": "YYYY-MM-DD", "sort_order": 1, "template_id": 42, "created_at": "2026-06-01T10:00:00+00:00"},
    {"id": 101, "name": "invoice_number", "format_requirement": "", "sort_order": 2, "template_id": 42, "created_at": "2026-06-01T10:00:00+00:00"},
    {"id": 103, "name": "vendor_name", "format_requirement": "Company name, no suffix", "sort_order": 3, "template_id": 42, "created_at": "2026-07-16T09:05:00+00:00"}
  ],
  "has_more": false,
  "next_page_token": null
}
```

---

Source: https://imagetotable.ai/developers/reference/templates-fields
