> This page is for version v2025-04-21.
> For other versions, use one of these documentation indexes:
> - v2026-02-09 (default): https://docs.extend.ai/2026-02-09/llms.txt
> - v2025-04-21: https://docs.extend.ai/2025-04-21/llms.txt
> - v2024-12-23: https://docs.extend.ai/2024-12-23/llms.txt

> ## Documentation Index
> Fetch the complete documentation index at: https://docs.extend.ai/llms.txt
> Use this file to discover all available pages before exploring further.
>
> ## API version
> The current API version is `2026-02-09`, served at the site root (no version prefix in URLs).
> If this page URL contains `/2025-04-21/` or `/2024-12-23/`, you are reading an older API version.
> Prefer the current docs at https://docs.extend.ai/llms.txt unless the user explicitly needs that older version.
> Do not treat older-version pages as the source of truth for new integrations.

# Edit File

> Edit and manipulate PDF documents by detecting and filling form fields.

The Edit endpoint allows you to programmatically edit PDF documents by detecting form fields and filling them with provided data. This endpoint is ideal for:

* Automatically filling out PDF forms
* Pre-populating documents with customer data
* Generating filled documents at scale

## Tutorial and explanation video

## Quick Start

**`Node.js`**

```javascript Node.js
const editDocument = async () => {
  const response = await fetch("https://api.extend.ai/edit", {
    method: "POST",
    headers: {
      Authorization: "Bearer <API_TOKEN>",
      "Content-Type": "application/json",
      "x-extend-api-version": "2025-04-21",
    },
    body: JSON.stringify({
      file: {
        fileUrl: "https://example.com/documents/form.pdf",
      },
      config: {
        engineVersion: "1.0.0",
        instructions: "Fill out the form with the provided data",
        advancedOptions: {
          flattenPdf: true,
        },
      },
    }),
  });

  if (!response.ok) {
    const error = await response.json();
    console.error("Error:", error);
    return;
  }

  const data = await response.json();
  console.log("Document edited successfully:", data);
};

editDocument();
```

**`Python`**

```python Python
import requests

def edit_document():
    url = "https://api.extend.ai/edit"
    headers = {
        "Authorization": "Bearer <API_TOKEN>",
        "Content-Type": "application/json",
        "x-extend-api-version": "2025-04-21"
    }
    payload = {
        "file": {
            "fileUrl": "https://example.com/documents/form.pdf"
        },
        "config": {
            "engineVersion": "1.0.0",
            "instructions": "Fill out the form with the provided data",
            "advancedOptions": {
                "flattenPdf": True
            }
        }
    }

    response = requests.post(url, json=payload, headers=headers)
    response.raise_for_status()
    
    print("Document edited successfully:", response.json())
    return response.json()

edit_document()
```

**`cURL`**

```bash cURL
curl -X POST https://api.extend.ai/edit \
  -H "Authorization: Bearer <API_TOKEN>" \
  -H "Content-Type: application/json" \
  -H "x-extend-api-version: 2025-04-21" \
  -d '{
    "file": {
      "fileName": "form.pdf",
      "fileUrl": "https://example.com/documents/form.pdf"
    },
    "config": {
      "engineVersion": "1.0.0",
      "instructions": "Fill out the form with the provided data",
      "advancedOptions": {
        "flattenPdf": true
      }
    }
  }'
```

---

## Endpoints

### POST /edit

Edit a PDF document synchronously. The request will wait for the edit operation to complete (up to 5 minutes) before returning results.

**Request Body**

| Field                  | Type   | Required | Description                                                                                                                         |
| ---------------------- | ------ | -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| `file`                 | object | Yes†     | File to edit                                                                                                                        |
| `file.fileName`        | string | No       | Name of the file                                                                                                                    |
| `file.fileUrl`         | string | Yes\*    | URL to download the file                                                                                                            |
| `file.fileId`          | string | Yes\*    | Existing Extend file ID                                                                                                             |
| `templateId`           | string | Yes†     | ID of a saved [edit template](#reuse-a-saved-template) to run against, in place of `file`                                           |
| `config`               | object | Yes      | Configuration for the edit operation                                                                                                |
| `config.engineVersion` | string | No       | Edit engine version. Use an exact version for reproducible results, or `latest` for the latest stable version. Defaults to `1.0.0`. |

†Exactly one of `file` or `templateId` must be provided.
\*When `file` is provided, one of `fileUrl` or `fileId` must be set.

### Reuse a saved template

Instead of passing a file directly, pass a saved edit template's ID (`edt_...`) as the top-level `templateId` field and Extend will reuse the template's file and configuration (schema, instructions, engine version, and advanced options) for the run. Any `config` values you also pass in the request take precedence over the template's saved values.

```json
{
  "templateId": "edt_xK9mLPqRtN3vS8wF5hB2cQ"
}
```

Retrieve a template's saved details with [Get Edit Template](https://docs.extend.ai/2025-04-21/api-reference/endpoints/edit/get-edit-template). If the template doesn't exist or belongs to another workspace or organization, the request fails with a `404` or `403` respectively.

**Response**

```json
{
  "editRun": {
    "object": "edit_run",
    "id": "edit_run_xK9mLPqRtN3vS8wF5hB2cQ",
    "fileId": "file_Zk9mNP12Qw4yTv8BdR3H",
    "editedFile": {
      "fileId": "file_Ab3cDE45Fg6hIj7KlM8nO",
      "downloadUrl": "https://extend-ai-files.s3.amazonaws.com/..."
    },
    "status": "PROCESSED",
    "config": {
      "engineVersion": "1.0.0",
      "instructions": "Fill out the form with the provided data"
    },
    "output": {},
    "metrics": {
      "processingTimeMs": 1234
    },
    "usage": {
      "credits": 1
    }
  }
}
```

---

### POST /editor_runs

Edit a PDF document. Returns immediately with an editor run ID that can be used to poll for results.

**Request Body**

Same as `POST /edit`.

**Response**

```json
{
  "object": "edit_run_status",
  "id": "editor_run_xK9mLPqRtN3vS8wF5hB2cQ",
  "status": "PROCESSING"
}
```

---

### GET /editor_runs/\{id}

Retrieve the status and results of an editor run.

**Path Parameters**

| Parameter | Type   | Description       |
| --------- | ------ | ----------------- |
| `id`      | string | The editor run ID |

**Response (Processing)**

```json
{
  "editRun": {
    "object": "edit_run_status",
    "id": "editor_run_xK9mLPqRtN3vS8wF5hB2cQ",
    "status": "PROCESSING"
  }
}
```

**Response (Completed)**

```json
{
  "editRun": {
    "object": "edit_run",
    "id": "editor_run_xK9mLPqRtN3vS8wF5hB2cQ",
    "fileId": "file_Zk9mNP12Qw4yTv8BdR3H",
    "editedFile": {
      "fileId": "file_Ab3cDE45Fg6hIj7KlM8nO",
      "downloadUrl": "https://extend-ai-files.s3.amazonaws.com/..."
    },
    "status": "PROCESSED",
    "config": { ... },
    "output": { ... },
    "metrics": { "processingTimeMs": 1234 },
    "usage": { "credits": 1 }
  }
}
```

---

### DELETE /editor_runs/\{id}

Delete an edit run and all associated data. This operation is permanent and cannot be undone.

**Path Parameters**

| Parameter | Type   | Description     |
| --------- | ------ | --------------- |
| `id`      | string | The edit run ID |

**Response**

```json
{
  "editorRunId": "editor_run_xK9mLPqRtN3vS8wF5hB2cQ",
  "message": "Editor run data has been successfully deleted."
}
```

---

## Configuration Options

The `config` object controls how documents are edited.

### Instructions

**`instructions`** `string`

Natural language instructions for the edit operation. Use this to provide context or specific guidance on how to fill the form.

```json
{
  "config": {
    "instructions": "Fill out all fields on the form. For the signature field, use 'John Doe'. Leave optional fields blank if no data is provided."
  }
}
```

### Schema Generation Instructions

**`schemaGenerationInstructions`** `string`

Additional instructions used when Extend needs to generate a schema from the PDF. This is useful when you want to bias field detection or naming without providing a full schema yourself.

```json
{
  "config": {
    "schemaGenerationInstructions": "Detect signature fields, preserve table structure, and use customer-friendly field names."
  }
}
```

### Schema

**`schema`** `object`

A JSON Schema defining the structure of fields to edit. The schema uses `extend_edit:*` properties to specify PDF field types, bounding box positions, text styling options, values to fill, and optional signature image fills.

#### Schema Types

The `type` property supports the following formats:

| Type Format             | Description                                  |
| ----------------------- | -------------------------------------------- |
| `["string", "null"]`    | Nullable string field (for text, signature)  |
| `["number", "null"]`    | Nullable number field (for text)             |
| `["integer", "null"]`   | Nullable integer field (for text)            |
| `["boolean", "null"]`   | Nullable boolean field (for checkbox, radio) |
| `"array"`               | Array field (for tables)                     |
| `"object"`              | Object field (for signatures)                |
| *(no type, use `enum`)* | Enum field (for radio, optionList, dropdown) |

#### Schema Properties

Each field in the schema can include:

| Property                        | Type            | Description                                                                                                                                                     |
| ------------------------------- | --------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`                          | string or array | JSON type (see table above)                                                                                                                                     |
| `description`                   | string          | Description of the field                                                                                                                                        |
| `extend_edit:field_type`        | string          | PDF field type: `"text"`, `"checkbox"`, `"radio"`, `"dropdown"`, `"optionList"`, `"signature"`, `"table"`                                                       |
| `extend_edit:bbox`              | object          | Bounding box with `left`, `top`, `right`, `bottom` (pixel coordinates)                                                                                          |
| `extend_edit:bboxes`            | array           | An array of bounding boxes used for radio enums only. Enums are matched on index to a bounding box in this array.                                               |
| `extend_edit:page_index`        | integer         | Zero-based page index                                                                                                                                           |
| `extend_edit:value`             | any             | The value to fill into this field                                                                                                                               |
| `extend_edit:image`             | object          | Image fill for signature fields. Use `{ "image_url": "https://..." }` with a PNG or JPEG URL.                                                                   |
| `extend_edit:text_edit_options` | object          | Text styling: `combing`, `maxLength`, `multiLine`, `fontSize`, `color` (RGB 0–255), `opacity` (0–1), and `font`. `fontColor` is a deprecated alias for `color`. |
| `extend_edit:column_width`      | number          | Width of the column as a percentage (for table fields)                                                                                                          |
| `extend_edit:row_heights`       | array           | Array of row height percentages (for array/table fields)                                                                                                        |
| `extend_edit:source_acroform`   | object          | Details about the original PDF form field. When Detect Form returns this property, include it unchanged in Edit requests.                                       |
| `items`                         | object          | Schema for array items (when type is "array")                                                                                                                   |
| `enum`                          | array           | Allowed values for enum/dropdown/radio fields                                                                                                                   |
| `extend:descriptions`           | array           | Human-readable labels for the values in `enum`, in the same order.                                                                                              |
| `maxItems`                      | integer         | Maximum number of rows for array/table fields                                                                                                                   |

#### Example Schema

```json
{
  "config": {
    "schema": {
      "type": "object",
      "required": ["policy_number", "policyholder_information_first_name"],
      "properties": {
        "policy_number": {
          "type": ["string", "null"],
          "description": "The policyholder's unique identification number.",
          "extend_edit:bbox": {
            "left": 0.250,
            "top": 0.242,
            "right": 0.454,
            "bottom": 0.267
          },
          "extend_edit:field_type": "text",
          "extend_edit:page_index": 0,
          "extend_edit:value": "12345678",
          "extend_edit:text_edit_options": {
            "combing": true,
            "maxLength": 8
          }
        },
        "policyholder_information_first_name": {
          "type": ["string", "null"],
          "description": "The first name of the policyholder.",
          "extend_edit:bbox": {
            "left": 0.608,
            "top": 0.313,
            "right": 0.880,
            "bottom": 0.338
          },
          "extend_edit:field_type": "text",
          "extend_edit:page_index": 0,
          "extend_edit:value": "John",
          "extend_edit:text_edit_options": {
            "combing": true,
            "maxLength": 9
          }
        },
        "is_permanent_address_change": {
          "type": ["boolean", "null"],
          "description": "Check this box if the address provided is a permanent change.",
          "extend_edit:bbox": {
            "left": 0.088,
            "top": 0.480,
            "right": 0.107,
            "bottom": 0.494
          },
          "extend_edit:field_type": "checkbox",
          "extend_edit:page_index": 0,
          "extend_edit:value": true
        },
        "patient_information_sex_male": {
          "type": ["boolean", "null"],
          "description": "A checkbox to indicate if the patient's sex is Male.",
          "extend_edit:bbox": {
            "left": 0.137,
            "top": 0.570,
            "right": 0.156,
            "bottom": 0.585
          },
          "extend_edit:field_type": "checkbox",
          "extend_edit:page_index": 0,
          "extend_edit:value": false
        }
      },
      "additionalProperties": false
    }
  }
}
```

> **Note**
>
> Field values are specified directly on each field using `extend_edit:value`. This replaces the legacy `input` object approach.

#### Signature Image Fills

For signature fields, you can provide an image instead of a text value:

```json
{
  "type": "object",
  "extend_edit:field_type": "signature",
  "extend_edit:image": {
    "image_url": "https://example.com/signature.png"
  }
}
```

#### Combed Fields

For fields that require character-by-character input (like SSN, phone numbers, or policy numbers), use `combing: true` with a `maxLength`:

```json
{
  "extend_edit:text_edit_options": {
    "combing": true,
    "maxLength": 9
  }
}
```

For fields that should wrap across multiple lines, set `multiLine: true`:

```json
{
  "extend_edit:text_edit_options": {
    "multiLine": true
  }
}
```

#### Native AcroForm metadata

Detect Form may return `extend_edit:source_acroform` for PDF form fields. Keep it unchanged when adding `extend_edit:value` and sending the schema to Edit. `fieldName` and `fieldType` describe the field, `optionMap` lists its supported choices, and `optionValue` identifies the value for a selected option.

#### Text appearance

Use `color` for an RGB text color and `opacity` for text opacity. RGB channels are integers from `0` to `255`; opacity ranges from `0` to `1`. `fontColor` remains accepted as a deprecated alias for `color`.

### Advanced Options

**`advancedOptions.flattenPdf`** `boolean`

When enabled, flattens the PDF after editing, making form fields non-editable. This is useful for generating final documents. The default is `true` for Edit `1.0.0` and `0.0.1`, and `false` for `1.0.0-beta`.

**`advancedOptions.tableParsingEnabled`** `boolean`

When enabled, parses table structures in the document. Default: `false`.

```json
{
  "config": {
    "advancedOptions": {
      "flattenPdf": true,
      "tableParsingEnabled": false
    }
  }
}
```

**`advancedOptions.radioEnumsEnabled`** `boolean`

When enabled, radio groups are represented as enums so only one option can be selected.

The default is `true` for Edit `1.0.0` and `1.0.0-beta`, and `false` for `0.0.1`.

**`advancedOptions.nativeFieldsOnly`** `boolean`

When enabled, only native AcroForm fields from the PDF are used in the schema.

**`advancedOptions.conditionalGenerationEnabled`** `boolean`

When enabled, Extend reads requirements explicitly stated in the form and adds root-level JSON Schema conditional validation rules to a generated edit schema. The rules validate generated field values when the schema is used for an edit; they do not add interactive UI behavior. Default: `false`.

If an Edit run cannot generate values that satisfy the generated conditionals, the run fails with `SCHEMA_VALIDATION_ERROR`.

This option applies only when Extend generates the schema. If you provide `config.schema`, include any conditional rules directly in that schema.

To learn more about conditional keywords, see [Conditional schema validation](https://json-schema.org/understanding-json-schema/reference/conditionals) in the JSON Schema documentation.

---

## Status Values

| Status       | Description                           |
| ------------ | ------------------------------------- |
| `PROCESSING` | The file is being edited              |
| `PROCESSED`  | The edit completed successfully       |
| `FAILED`     | The edit failed (see `failureReason`) |

---

## Error Handling

When an error occurs, the API returns a structured error response:

```json
{
  "code": "FILE_TYPE_NOT_SUPPORTED",
  "message": "Only PDF files are supported for editing",
  "requestId": "req_abc123",
  "retryable": false
}
```

### Error Codes

| Error Code                 | Description                              | Retryable |
| -------------------------- | ---------------------------------------- | --------- |
| `INVALID_CONFIG_OPTIONS`   | Invalid configuration options            | ❌         |
| `UNABLE_TO_DOWNLOAD_FILE`  | Could not download the file from the URL | ❌         |
| `FILE_TYPE_NOT_SUPPORTED`  | File type not supported (only PDFs)      | ❌         |
| `FILE_SIZE_TOO_LARGE`      | File exceeds maximum size                | ❌         |
| `CORRUPT_FILE`             | File is corrupt                          | ❌         |
| `OCR_ERROR`                | OCR processing error                     | ✅         |
| `PASSWORD_PROTECTED_FILE`  | File is password protected               | ❌         |
| `FAILED_TO_CONVERT_TO_PDF` | PDF conversion failed                    | ❌         |
| `SCHEMA_VALIDATION_FAILED` | Schema validation error                  | ❌         |
| `INTERNAL_ERROR`           | Internal server error                    | ✅         |

---

## Examples

### Filling a Simple Form with Schema

```javascript
const response = await fetch("https://api.extend.ai/edit", {
  method: "POST",
  headers: {
    Authorization: "Bearer <API_TOKEN>",
    "Content-Type": "application/json",
    "x-extend-api-version": "2025-04-21",
  },
  body: JSON.stringify({
    file: {
      fileUrl: "https://example.com/application-form.pdf",
    },
    config: {
      schema: {
        type: "object",
        properties: {
          applicant_name: {
            type: ["string", "null"],
            "extend_edit:field_type": "text",
            "extend_edit:page_index": 0,
            "extend_edit:bbox": { left: 0.1, top: 0.2, right: 0.4, bottom: 0.23 },
            "extend_edit:value": "Jane Smith",
          },
          application_date: {
            type: ["string", "null"],
            "extend_edit:field_type": "text",
            "extend_edit:page_index": 0,
            "extend_edit:bbox": { left: 0.5, top: 0.2, right: 0.8, bottom: 0.23 },
            "extend_edit:value": "2024-03-21",
          },
          email_address: {
            type: ["string", "null"],
            "extend_edit:field_type": "text",
            "extend_edit:page_index": 0,
            "extend_edit:bbox": { left: 0.1, top: 0.3, right: 0.4, bottom: 0.33 },
            "extend_edit:value": "jane@example.com",
          },
        },
        required: ["applicant_name"],
        additionalProperties: false,
      },
      advancedOptions: {
        flattenPdf: true,
      },
    },
  }),
});

const data = await response.json();
// Download the filled PDF
const downloadUrl = data.editRun.editedFile.downloadUrl;
```

### Async Processing with Polling

```javascript
// Start async edit
const startResponse = await fetch("https://api.extend.ai/editor_runs", {
  method: "POST",
  headers: {
    Authorization: "Bearer <API_TOKEN>",
    "Content-Type": "application/json",
    "x-extend-api-version": "2025-04-21",
  },
  body: JSON.stringify({
    file: { fileUrl: "https://example.com/large-form.pdf" },
    config: {
      schema: {
        type: "object",
        properties: {
          name: {
            type: ["string", "null"],
            "extend_edit:field_type": "text",
            "extend_edit:page_index": 0,
            "extend_edit:bbox": { left: 0.1, top: 0.1, right: 0.5, bottom: 0.13 },
            "extend_edit:value": "John Doe",
          },
        },
        additionalProperties: false,
      },
    },
  }),
});

const startData = await startResponse.json();
const editorRunId = startData.id;

// Poll for completion
let result;
while (true) {
  const statusResponse = await fetch(
    `https://api.extend.ai/editor_runs/${editorRunId}`,
    {
      headers: {
        Authorization: "Bearer <API_TOKEN>",
        "x-extend-api-version": "2025-04-21",
      },
    }
  );

  const statusData = await statusResponse.json();
  result = statusData.editRun;

  if (result.status === "PROCESSED" || result.status === "FAILED") {
    break;
  }

  // Wait before polling again
  await new Promise(resolve => setTimeout(resolve, 1000));
}

if (result.status === "PROCESSED") {
  console.log("Output file:", result.editedFile.downloadUrl);
} else {
  console.error("Edit failed:", result.failureReason);
}
```

---

## Best Practices

1. **Use async for large files** - For files larger than a few MB or complex forms, use the async endpoint to avoid timeouts.

2. **Flatten for final documents** - Enable `flattenPdf: true` when generating final documents to prevent further editing.

3. **Use `extend_edit:value` on each field** - Specify values directly on each field in your schema using the `extend_edit:value` property.

4. **Use instructions for context** - Provide clear instructions when field mapping isn't straightforward.

5. **Handle errors gracefully** - Implement retry logic for retryable errors like `OCR_ERROR` and `INTERNAL_ERROR`.

6. **Enable table parsing for forms with tables** - Set `tableParsingEnabled: true` for forms with large regions of empty table cells you want filled.

7. **Use correct bounding box format** - Bounding boxes use `left`, `top`, `right`, `bottom` coordinates (pixel values).