Edit File

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

1import { ExtendClient } from "extend-ai";
2
3const client = new ExtendClient({ token: "YOUR_API_KEY" });
4
5// client.edit() is for testing, we recommend using webhooks or polling with client.editRuns.createAndPoll() in production
6const result = await client.edit({
7 file: {
8 url: "https://example.com/documents/form.pdf",
9 },
10 config: {
11 instructions: "Fill out the form with the provided data",
12 advancedOptions: {
13 flattenPdf: true
14 }
15 }
16});
17
18console.log("Document edited successfully:", result);
19// Download the filled PDF
20const downloadUrl = result.output?.editedFile?.presignedUrl;

Endpoints

POST /edit_runs

Create an edit run to edit a PDF document. All edit operations are asynchronous - the endpoint returns immediately with an edit run ID that can be used to poll for results.

Request Body

FieldTypeRequiredDescription
fileobjectYesFile to edit
file.namestringNoName of the file
file.urlstringYes*URL to download the file
file.idstringYes*Existing Extend file ID
configobjectYesConfiguration for the edit operation

*One of url or id must be provided.

Response

1{
2 "object": "edit_run",
3 "id": "edr_xK9mLPqRtN3vS8wF5hB2cQ",
4 "file": {
5 "object": "file",
6 "id": "file_Zk9mNP12Qw4yTv8BdR3H",
7 "name": "form.pdf",
8 "type": "PDF"
9 },
10 "status": "PROCESSING",
11 "failureReason": null,
12 "config": {
13 "instructions": "Fill out the form with the provided data"
14 },
15 "output": null,
16 "metrics": null,
17 "usage": null
18}

GET /edit_runs/{id}

Retrieve the status and results of an edit run. Poll this endpoint until status is PROCESSED or FAILED.

Path Parameters

ParameterTypeDescription
idstringThe edit run ID

Response (Processing)

1{
2 "object": "edit_run",
3 "id": "edr_xK9mLPqRtN3vS8wF5hB2cQ",
4 "file": { ... },
5 "status": "PROCESSING",
6 "failureReason": null,
7 "config": { ... },
8 "output": null,
9 "metrics": null,
10 "usage": null
11}

Response (Completed)

1{
2 "object": "edit_run",
3 "id": "edr_xK9mLPqRtN3vS8wF5hB2cQ",
4 "file": {
5 "object": "file",
6 "id": "file_Zk9mNP12Qw4yTv8BdR3H",
7 "name": "form.pdf",
8 "type": "PDF"
9 },
10 "status": "PROCESSED",
11 "failureReason": null,
12 "config": { ... },
13 "output": {
14 "editedFile": {
15 "id": "file_Ab3cDE45Fg6hIj7KlM8nO",
16 "presignedUrl": "https://extend-ai-files.s3.amazonaws.com/..."
17 },
18 "filledValues": { ... }
19 },
20 "metrics": { "processingTimeMs": 1234 },
21 "usage": { "credits": 1 }
22}

DELETE /edit_runs/{id}

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

Path Parameters

ParameterTypeDescription
idstringThe edit run ID

Response

1{
2 "id": "edr_xK9mLPqRtN3vS8wF5hB2cQ"
3}

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.

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

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, and values to fill.

Schema Types

The type property supports the following formats:

Type FormatDescription
["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:

PropertyTypeDescription
typestring or arrayJSON type (see table above)
descriptionstringDescription of the field
extend_edit:field_typestringPDF field type: "text", "checkbox", "radio", "dropdown", "optionList", "signature", "table"
extend_edit:bboxobjectBounding box with left, top, right, bottom (pixel coordinates)
extend_edit:page_indexintegerZero-based page index
extend_edit:valueanyThe value to fill into this field
extend_edit:text_edit_optionsobjectText styling: combing, maxLength, fontSize, fontColor, font
extend_edit:column_widthnumberWidth of the column as a percentage (for table fields)
extend_edit:row_heightsarrayArray of row height percentages (for array/table fields)
itemsobjectSchema for array items (when type is “array”)
enumarrayAllowed values for enum/dropdown/radio fields
maxItemsintegerMaximum number of rows for array/table fields

Example Schema

1{
2 "config": {
3 "schema": {
4 "type": "object",
5 "required": ["policy_number", "policyholder_information_first_name"],
6 "properties": {
7 "policy_number": {
8 "type": ["string", "null"],
9 "description": "The policyholder's unique identification number.",
10 "extend_edit:bbox": {
11 "left": 0.250,
12 "top": 0.242,
13 "right": 0.454,
14 "bottom": 0.267
15 },
16 "extend_edit:field_type": "text",
17 "extend_edit:page_index": 0,
18 "extend_edit:value": "12345678",
19 "extend_edit:text_edit_options": {
20 "combing": true,
21 "maxLength": 8
22 }
23 },
24 "policyholder_information_first_name": {
25 "type": ["string", "null"],
26 "description": "The first name of the policyholder.",
27 "extend_edit:bbox": {
28 "left": 0.608,
29 "top": 0.313,
30 "right": 0.880,
31 "bottom": 0.338
32 },
33 "extend_edit:field_type": "text",
34 "extend_edit:page_index": 0,
35 "extend_edit:value": "John",
36 "extend_edit:text_edit_options": {
37 "combing": true,
38 "maxLength": 9
39 }
40 },
41 "is_permanent_address_change": {
42 "type": ["boolean", "null"],
43 "description": "Check this box if the address provided is a permanent change.",
44 "extend_edit:bbox": {
45 "left": 0.088,
46 "top": 0.480,
47 "right": 0.107,
48 "bottom": 0.494
49 },
50 "extend_edit:field_type": "checkbox",
51 "extend_edit:page_index": 0,
52 "extend_edit:value": true
53 },
54 "patient_information_sex_male": {
55 "type": ["boolean", "null"],
56 "description": "A checkbox to indicate if the patient's sex is Male.",
57 "extend_edit:bbox": {
58 "left": 0.137,
59 "top": 0.570,
60 "right": 0.156,
61 "bottom": 0.585
62 },
63 "extend_edit:field_type": "checkbox",
64 "extend_edit:page_index": 0,
65 "extend_edit:value": false
66 }
67 },
68 "additionalProperties": false
69 }
70 }
71}

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

Combed Fields

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

1{
2 "extend_edit:text_edit_options": {
3 "combing": true,
4 "maxLength": 9
5 }
6}

Advanced Options

When enabled, automatically detects form fields in the document. Default: true.

advancedOptions.flattenPdf boolean

When enabled, flattens the PDF after editing, making form fields non-editable. This is useful for generating final documents. Default: false.

advancedOptions.tableParsingEnabled boolean

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

1{
2 "config": {
3 "advancedOptions": {
4 "flattenPdf": true,
5 "tableParsingEnabled": false
6 }
7 }
8}

Status Values

StatusDescription
PROCESSINGThe file is being edited
PROCESSEDThe edit completed successfully
FAILEDThe edit failed (see failureReason)

Error Handling

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

1{
2 "code": "FILE_TYPE_NOT_SUPPORTED",
3 "message": "Only PDF files are supported for editing",
4 "requestId": "req_abc123",
5 "retryable": false
6}

Error Codes

Error CodeDescriptionRetryable
INVALID_CONFIG_OPTIONSInvalid configuration options
UNABLE_TO_DOWNLOAD_FILECould not download the file from the URL
FILE_TYPE_NOT_SUPPORTEDFile type not supported (only PDFs)
FILE_SIZE_TOO_LARGEFile exceeds maximum size
CORRUPT_FILEFile is corrupt
OCR_ERROROCR processing error
PASSWORD_PROTECTED_FILEFile is password protected
FAILED_TO_CONVERT_TO_PDFPDF conversion failed
SCHEMA_VALIDATION_FAILEDSchema validation error
INTERNAL_ERRORInternal server error

Examples

Filling a Simple Form with Schema

1// /edit is for testing, we recommend using webhooks or polling with /edit_runs in production
2const response = await fetch("https://api.extend.ai/edit", {
3 method: "POST",
4 headers: {
5 Authorization: "Bearer <API_TOKEN>",
6 "Content-Type": "application/json",
7 "x-extend-api-version": "2026-02-09"
8 },
9 body: JSON.stringify({
10 file: {
11 url: "https://example.com/application-form.pdf"
12 },
13 config: {
14 schema: {
15 type: "object",
16 properties: {
17 applicant_name: {
18 type: ["string", "null"],
19 "extend_edit:field_type": "text",
20 "extend_edit:page_index": 0,
21 "extend_edit:bbox": { left: 0.1, top: 0.2, right: 0.4, bottom: 0.23 },
22 "extend_edit:value": "Jane Smith"
23 },
24 application_date: {
25 type: ["string", "null"],
26 "extend_edit:field_type": "text",
27 "extend_edit:page_index": 0,
28 "extend_edit:bbox": { left: 0.5, top: 0.2, right: 0.8, bottom: 0.23 },
29 "extend_edit:value": "2024-03-21"
30 },
31 email_address: {
32 type: ["string", "null"],
33 "extend_edit:field_type": "text",
34 "extend_edit:page_index": 0,
35 "extend_edit:bbox": { left: 0.1, top: 0.3, right: 0.4, bottom: 0.33 },
36 "extend_edit:value": "jane@example.com"
37 }
38 },
39 required: ["applicant_name"],
40 additionalProperties: false
41 },
42 advancedOptions: {
43 flattenPdf: true
44 }
45 }
46 }),
47});
48
49const data = await response.json();
50// Download the filled PDF
51const downloadUrl = data.output.editedFile.presignedUrl;

Async Processing with Polling

1// Start edit run
2const startResponse = await fetch("https://api.extend.ai/edit_runs", {
3 method: "POST",
4 headers: {
5 Authorization: "Bearer <API_TOKEN>",
6 "Content-Type": "application/json",
7 "x-extend-api-version": "2026-02-09"
8 },
9 body: JSON.stringify({
10 file: { url: "https://example.com/large-form.pdf" },
11 config: {
12 schema: {
13 type: "object",
14 properties: {
15 name: {
16 type: ["string", "null"],
17 "extend_edit:field_type": "text",
18 "extend_edit:page_index": 0,
19 "extend_edit:bbox": { left: 0.1, top: 0.1, right: 0.5, bottom: 0.13 },
20 "extend_edit:value": "John Doe"
21 }
22 },
23 additionalProperties: false
24 }
25 }
26 }),
27});
28
29const startData = await startResponse.json();
30const editRunId = startData.id;
31
32// Poll for completion
33let result;
34while (true) {
35 const statusResponse = await fetch(
36 `https://api.extend.ai/edit_runs/${editRunId}`,
37 {
38 headers: {
39 Authorization: "Bearer <API_TOKEN>",
40 "x-extend-api-version": "2026-02-09"
41 }
42 }
43 );
44
45 const statusData = await statusResponse.json();
46 result = statusData;
47
48 if (result.status === "PROCESSED" || result.status === "FAILED") {
49 break;
50 }
51
52 // Wait before polling again
53 await new Promise(resolve => setTimeout(resolve, 1000));
54}
55
56if (result.status === "PROCESSED") {
57 console.log("Output file:", result.output.editedFile.presignedUrl);
58} else {
59 console.error("Edit failed:", result.failureReason);
60}

Best Practices

  1. Implement polling for all operations - All edit runs are async. Poll GET /edit_runs/{id} until status is PROCESSED or FAILED.

  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).