> This page is for version v2026-02-09 (default).
> 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.

# Editing Best Practices

> Practical tips for reliable PDF editing — choosing instructions vs schema, flattening, table parsing, and moving to production.

This guide covers practical tips for getting reliable results from Edit: choosing how to drive a run, controlling the output, and running at scale.

---

## Prefer a schema for precision

Natural-language `instructions` are the fastest way to get started, but a `schema` with `extend_edit:value` on each field gives you exact, repeatable control over what gets filled and where. Reach for a schema whenever you run the same form type repeatedly or need deterministic output.

```json
{
  "config": {
    "schema": {
      "type": "object",
      "properties": {
        "first_name": {
          "type": ["string", "null"],
          "extend_edit:field_type": "text",
          "extend_edit:value": "Jordan"
        }
      },
      "additionalProperties": false
    }
  }
}
```

Don't have a schema yet? [Detect Form](/editing/detect-form) detects a form's fields and returns one with positions annotated, so you can start from a real layout instead of hand-writing field positions. See [Schema](/editing/configuration#schema).

---

## Use instructions for context

When field mapping isn't obvious — ambiguous labels, fields that depend on conditions — add `instructions` to guide how those fields should be filled. You can combine `instructions` with a `schema`: the schema pins the values you know, and instructions steer the rest.

```json
{
  "config": {
    "instructions": "Use the Single filing status. For any date fields, use today's date. Leave optional fields blank."
  }
}
```

See [Instructions](/editing/configuration#instructions).

---

## Flatten final documents

Set `advancedOptions.flattenPdf` to `true` when you're generating a document for delivery, so the filled fields can't be edited further. Flattening is on by default; set it to `false` if you need the output to remain an editable form.

```json
{
  "config": {
    "advancedOptions": { "flattenPdf": true }
  }
}
```

See [Flatten the PDF](/editing/configuration#advancedoptionsflattenpdf).

---

## Enable table parsing for tabular forms

For forms with large table regions you want filled, set `advancedOptions.tableParsingEnabled` to `true` so Extend parses those regions as arrays of objects you can populate.

```json
{
  "config": {
    "advancedOptions": { "tableParsingEnabled": true }
  }
}
```

See [Table parsing](/editing/configuration#advancedoptionstableparsingenabled).

---

## Download the edited file promptly

`output.editedFile.presignedUrl` expires **15 minutes** after the run completes. Fetch and store the file as soon as the run reaches `PROCESSED` — don't hold the URL for later use. The edited file's `id` is reusable as input to other endpoints if you need to reprocess it.

---

## Recipes

Ready-to-run `config` blocks for common scenarios (comments explain each setting). For field-level options and defaults, see [Configuration](/editing/configuration).

### Precise, repeatable fill

```json
{
  "config": {
    "schema": {
      "type": "object",
      "properties": {
        "first_name": {
          "type": ["string", "null"],
          "extend_edit:field_type": "text",
          "extend_edit:value": "Jordan"
        },
        "ssn": {
          "type": ["string", "null"],
          "extend_edit:field_type": "text",
          "extend_edit:value": "123-45-6789",
          "extend_edit:text_edit_options": { "combing": true, "maxLength": 9 }  // character-by-character box
        }
      },
      "additionalProperties": false
    },
    "advancedOptions": { "flattenPdf": true }  // non-editable final document
  }
}
```

### Quick fill from instructions

```json
{
  "config": {
    "instructions": "Fill the applicant's name and today's date. Leave optional fields blank.",  // Extend detects and fills fields
    "advancedOptions": { "flattenPdf": false }  // keep the form editable
  }
}
```

### Tabular form

```json
{
  "config": {
    "instructions": "Fill the line-items table with the provided rows.",
    "advancedOptions": {
      "tableParsingEnabled": true,  // parse table regions as arrays of objects
      "flattenPdf": true
    }
  }
}
```

---

## Move to production with async processing

The quick start and the examples above use the synchronous `/edit` endpoint — the fastest way to try Edit and iterate on config. When you're ready to run Edit in production, switch to the asynchronous `/edit_runs` endpoint.

**Why the sync `/edit` endpoint isn't built for production:**

* It has a **5-minute timeout** — large or complex documents can exceed it and fail.
* It holds a connection open for the entire run, which is brittle for big files and bursty traffic.
* It's intended for onboarding and testing, not sustained workloads.

**What async (`/edit_runs`) gives you:**

* Reliable handling of large documents without timeouts.
* Results via polling (`GET /edit_runs/{id}`) or webhooks, so you're not holding connections open.
* A better fit for batch and high-volume pipelines.

The SDK helpers (`client.edit_runs.create_and_poll()` / `client.editRuns.createAndPoll()`) create a run and poll until it reaches a terminal state for you. See [Async Processing](/general/async-processing) for the full comparison, polling options, and webhook setup, and [Error Handling](/editing/error-handling) for handling failed runs.