Extend Agent Context
Context file for AI coding assistants building on the Extend document processing platform.
What is Extend?
Extend is a platform for building, evaluating, and deploying AI-powered document processing. It provides APIs and SDKs for:
- Extraction — Pull structured data from documents using a JSON Schema
- Classification — Categorize documents by type
- Splitting — Divide multi-page documents into sections
- Parsing — Convert documents into clean, structured text (markdown, etc.)
- Editing — Detect and fill PDF form fields
- Workflows — Orchestrate multiple processors into pipelines with conditionals, human review, webhooks, and more
Full documentation: https://docs.extend.ai Searchable docs index: https://docs.extend.ai/llms.txt
Authentication
All API requests require Bearer token authentication and an API version header. If using an SDK, authentication and versioning are handled automatically — the details below apply to raw HTTP requests only.
Get your API key from the Developers page in the Extend dashboard.
Omitting x-extend-api-version on raw HTTP requests returns an error. SDKs set this automatically.
API Versions
The API is versioned by date via the x-extend-api-version header. The latest version is 2026-02-09. SDKs target the correct version automatically when kept up to date. For the full list of versions, their status, and per-version changes, see the API versioning docs.
If you are on an older version, see the migration guide for breaking changes in 2026-02-09. Key changes:
- Dedicated endpoints per resource type (
/extract,/classify,/split) replace the generic/processor_runsendpoint - New ID prefixes: extractors use
ex_, extract runs useexr_, classifiers usecl_, splitters usesp_ - Synchronous processing support on all endpoints (new
/extract,/classify,/splitsync endpoints) - Simplified responses: single objects no longer wrapped in containers; list responses standardized to
{ "object": "list", "data": [...] } - Inline configuration: pass extractor/classifier/splitter config inline without pre-creating a resource — useful for managing schemas entirely in code
- SDK polling helpers:
createAndPoll/create_and_pollmethods with exponential backoff built into updated SDKs
Migration path: Update your SDK to the latest version (automatically targets 2026-02-09), then migrate endpoint-by-endpoint. The old /processor_runs and /processors endpoints still work on older API versions but are now under Legacy in the docs.
Docs: https://docs.extend.ai/api-reference/api-versioning
SDKs
Official SDKs are available for Python, TypeScript, Java, and Go. All are generated from the API spec and target the latest API version automatically.
Python:
TypeScript:
Java (Gradle):
Go:
Community SDK:
- Haskell — maintained by Mercury Technologies: https://github.com/MercuryTechnologies/extend
The Python, TypeScript, and Java SDKs include polling helpers (create_and_poll / createAndPoll) for async operations, plus webhook signature verification utilities. The Go SDK ships neither — call Create and poll the run yourself (or use webhooks), and verify webhook signatures manually (HMAC-SHA256).
Docs: https://docs.extend.ai/sdks
CLI
The extend CLI runs every core operation from the shell, with no code to write. Reach for it for one-off tasks, exploration, and agent-driven actions you’d otherwise script with raw HTTP (creating extractors/classifiers/splitters/workflows, running a doc, kicking off an eval set). For durable application code, prefer an SDK above.
Install (any one):
Authenticate, then verify with a read-only command:
An EXTEND_API_KEY in the environment always wins. Interactive machines can instead run extend setup (browser sign-in via OAuth, or save an API key); check the credentials in effect with extend whoami.
Common commands (each <input> is a local path, a file_... ID, or an https:// URL):
Inspect runs with the typed commands under each verb (extend extract runs list, extend workflows runs watch <id>, and so on). Manage resources with extend <noun> ... (extractors, classifiers, splitters, workflows, files, evaluations, webhooks). Filter output with -o json --jq '<expr>', and run extend <command> --help for exact flags. The CLI is the source of truth. Teach your harness to use it with extend skill install, which writes the extend-cli skill to ~/.agents/skills/extend-cli/SKILL.md (symlinked into ~/.claude/skills/extend-cli for Claude Code).
Docs: https://docs.extend.ai/agent-quickstart
MCP Server
If your harness connects to MCP (Model Context Protocol) servers, Extend ships one: the full platform (parse, extract, classify, split, edit, workflows, files, webhooks, evaluations) as tools with built-in run polling and structured errors. Pick it over raw HTTP when your agent works through tool calls rather than code.
Connect to https://mcp.extend.ai/mcp and complete the OAuth browser sign-in.
Call get_me first to discover your granted workspace and environment targets; every run-scoped tool requires workspaceId + environment arguments. Once connected, the tool descriptions and server instructions carry the full interaction contract.
Setup instructions per client (Cursor, Claude, ChatGPT, VS Code, and others): https://docs.extend.ai/mcp.md
API Endpoints (2026-02-09)
Note on SDK method names vs REST paths: This document describes the REST API. SDK method names follow language conventions and may differ (e.g., REST
POST /extract_runsmaps to Pythonclient.extract_runs.create()and TypeScriptclient.extractRuns.create()). Always confirm exact method signatures against the SDK source or docs when writing code.
Base URL
SDKs accept a baseUrl (TypeScript) or base_url (Python) parameter to select the region.
Files
Extract
Classify
Split
Parse
Edit
Verify
Verify checks a single PDF, JPEG, or PNG for tampering, forgery, AI generation, AI edits, and more.
Request: file ({url} or {id}; no text/base64), optional config (engine: verify_agentic default or verify_light; engineVersion: latest default or e.g. 0.1.0; advancedOptions.requireParsing: light parses only when true, agentic always parses and rejects false; an existing parse of the file made with Verify’s default parse settings is reused unless the file is zero-retention), optional metadata. Unknown config keys return 400. Every supported check runs on every run; there is no signal allowlist.
Response output (when PROCESSED): riskLevel (LOW/MEDIUM/HIGH; LOW = nothing detected, never authenticity), summary, signals[] each with id (vs_), type (a Public Signal category), riskAssessment ({type: "LEVEL", level}), summary, evidence[] (evidenceId, type in value_comparison | validation | inventory | history | structural_pattern | model_prediction, data, locations[] with page (number from 1, width, height), top-left boundingBox (left/top/right/bottom), objectRefs, byteRange). config echoes engine, engineVersion, and advancedOptions.requireParsing. file is null once the input file is deleted. List items carry riskLevel (null until processed, and null again once a zero-retention result is purged) instead of output. Statuses: PROCESSING, PROCESSED, FAILED, CANCELLED. Failure reasons: FILE_TYPE_NOT_SUPPORTED, NO_APPLICABLE_SIGNALS, PARSE_FAILED, REQUEST_ABORTED, INTERNAL_ERROR.
Workflows
Evaluation Sets
Webhook Endpoints
Manage where Extend delivers events. The create response includes a signingSecret that is returned only once. Store it securely for signature verification.
Webhook Subscriptions
Subscribe an endpoint to events for a specific resource (e.g. a single workflow) instead of the endpoint’s global enabledEvents.
Common Patterns
Extract (sync) — Python
Extract (async with polling) — Python
Extract (sync) — TypeScript
Extract (async with polling) — TypeScript
Typed extraction with Zod — TypeScript
The TypeScript SDK supports inline Zod schemas with full type inference:
Extract (sync) — Go
The Go SDK is fully typed. It has no polling helper, so call Extract (sync) or ExtractRuns.Create and poll the run yourself.
Parse a document — Python
Parse (async with polling) — Python
Run a workflow — Python
Run a workflow — TypeScript
Verify a document (async with polling) — Python
Verify a document (sync) — TypeScript
Sync vs Async Processing
All processing endpoints (extract, classify, split, parse, edit) support both sync and async modes. Workflows are async-only.
- Sync (
POST /extract/ SDK:client.extract()) — Blocks until complete. Has a 5-minute timeout. Best for testing and small files. - Async (
POST /extract_runs/ SDK:client.extractRuns.createAndPoll()orclient.extract_runs.create_and_poll()) — Returns immediately with a run ID. Poll withGET /extract_runs/{id}or use webhooks. No timeout limit.
Use async for production workloads. Large documents can exceed the 5-minute sync timeout. SDK createAndPoll / create_and_poll methods are the recommended approach — they handle polling automatically with built-in backoff.
SDK polling helpers use a hybrid strategy: fast polling for 30 seconds, then gradual backoff up to 30-second intervals.
Terminal statuses: PROCESSED, FAILED, CANCELLED (also NEEDS_REVIEW, REJECTED for workflows).
Docs: https://docs.extend.ai/general/async-processing
Managing configs (recommended workflow)
Processor and workflow configs can get large and deeply nested, and create/update calls validate them strictly. When building these, write the config to a file in the project and submit it from there. Don’t hand-author it inline. If a request fails validation, the API returns the specific field path that’s invalid; edit just that part of the file and resubmit, instead of regenerating the entire config from scratch.
This applies to every config-bearing resource:
Suggested loop:
- Save the config as JSON, e.g.
extractor.config.json(or save the whole request body if that’s simpler for your call). - Create/update by loading the file, for example
--from-file extractor.config.jsonwith the CLI, orjson.load(open("extractor.config.json"))/JSON.parse(fs.readFileSync(...))in the SDKs. - On a validation error, read the returned field path, edit only that part of the file, and resubmit. Keep the file as the source of truth so each fix is incremental.
This keeps iterations cheap and avoids reintroducing earlier mistakes when a single field is wrong. Note that Extend normalizes configs on submit (see the schema rules below), so the stored config the API echoes back may differ slightly from your file. Diff against your file intentionally rather than expecting a byte-for-byte match.
Versioning: processors and workflows
Both processors and workflows have one editable draft and immutable published/deployed versions. Edits always land on the draft; publishing snapshots it. Nothing that references a specific version ever changes behaviour when you publish again.
Major vs minor is only a numbering signal: minor for changes that keep the output shape (descriptions, rules, base processor); major when the schema, classification types, or split identifiers change so downstream code must be updated.
Workflow steps reference processors with an explicit version ("latest", "draft", or "1.1"). Deploying a workflow version freezes that string, but "latest" still resolves at run time, so a fully reproducible deployed workflow needs pinned processor versions in its steps.
Recommended promotion loop: update the draft → run the evaluation set against "draft" → publish → move the version string in your config/workflow step → deploy the workflow.
Docs: https://docs.extend.ai/evaluation/publishing-processors (processors) and https://docs.extend.ai/workflows/workflow-versioning (workflows), all four SDKs.
Test environment
A test API key routes every request to an isolated test environment: same base URL, same code, no production data, no production webhooks. Workflow and processor definitions are shared between environments; runs and webhook deliveries are not. Create test keys and test webhook endpoints with Test Environment toggled on in Studio’s Developers tab. All SDKs read EXTEND_API_KEY; switch environments by switching the key. Docs: https://docs.extend.ai/general/test-environment-guide
Extraction Schema (JSON Schema)
Extractors use JSON Schema to define output structure. Key rules:
- Root must be
"type": "object" - All primitive fields must be nullable: use
"type": ["string", "null"]not"type": "string" - Objects and arrays cannot be nullable
- Max nesting depth: 5 levels
- Property names: letters, numbers, underscores, hyphens only
"required"arrays and"additionalProperties": falseare optional in the schema you submit. Extend normalizes your config on create/update by marking every listed propertyrequiredand injecting"additionalProperties": falseon all objects. The echoed-back config therefore won’t match yours byte-for-byte; that’s expected, not an error. Include them yourself if you want your stored schema to be explicit.
Supported types
Special Extend types
Enums
Enums must include null and only support string values. Use "extend:descriptions" for disambiguation:
Field descriptions
Use "description" to guide extraction. Use "extend:name" for display names without changing output keys.
Unsupported
anyOf, oneOf, allOf, regex patterns, conditional schemas, const.
Docs: https://docs.extend.ai/extraction/schema
Legacy: Fields Array schema
Extractors created before April 2025 may use the legacy “Fields Array” configuration instead of JSON Schema. Key differences:
- Fields Array used a
fieldsarray withid,name,type,descriptionper field. Output mixed data and metadata together within each field object. - JSON Schema uses a standard
schemaobject. Output cleanly separatesvalue(extracted data) frommetadata(confidence, citations) using path-based keys.
To migrate: Open your processor in Studio, click the three-dot menu, select “Migrate to JSON Schema.” This creates a new processor with the converted schema while preserving your original.
New extractors should always use JSON Schema. See the migration guide for full details.
Webhooks
Webhooks deliver HTTP POST notifications when processing events complete.
Setup
- Create an endpoint in the Extend dashboard under Developers > Webhook Endpoints
- Subscribe to events at global, workflow, or processor scope
- Choose delivery format: JSON (default) or Signed Download URL (for large payloads)
Key events
The table below lists common events. For the full list (including edit, lifecycle, and CRUD events for all resource types), see the webhook events docs.
Signature verification
Extend signs every webhook with HMAC-SHA256. Use the SDK’s built-in verification:
Python:
TypeScript:
Java:
The Go SDK has no verification helper. Verify the signature manually (steps below).
For manual verification:
- Extract
x-extend-request-timestampandx-extend-request-signatureheaders - Construct message:
v0:{timestamp}:{body} - HMAC-SHA256 with your signing secret
- Compare signatures; reject if timestamp > 5 minutes old
Docs: https://docs.extend.ai/webhooks/configuration
Workflows
Workflows chain processors into pipelines. Build them visually in Extend Studio or manage them entirely via the API (create, configure, version/deploy, and run — see the Workflows endpoints above).
Capabilities
- Extraction, classification, splitting steps
- Conditional routing based on extracted values or classification results
- Human review steps (pauses workflow for manual review)
- External data validation (call your API mid-workflow)
- Webhook response steps
- Formula calculations
- Parse step configuration
- Validation rules
Defining processor steps
EXTRACT, CLASSIFY, and SPLIT workflow steps accept either a saved processor reference or a full inline config. When config is present, provide exactly one source:
Inline extraction configs must include schema; schema-less extraction is not supported inside workflows. Inline classify/split routes use the IDs declared in their inline classifications. CONDITIONAL_EXTRACT rules remain saved-reference only. Full reference: https://docs.extend.ai/workflows/configuring-workflows
Running a workflow via API
Via SDK, use client.workflowRuns.createAndPoll() (TypeScript) or client.workflow_runs.create_and_poll() (Python) — see Common Patterns above. Raw HTTP example:
Workflow run statuses
Retryable failure reasons
These failures are transient and safe to retry automatically:
INTERNAL_ERROR— Unexpected server errorDOCUMENT_PROCESSOR_ERROR— Extraction step failed after retries
Non-retryable:
INVALID_WORKFLOW— Workflow configuration errorFAILED_TO_PROCESS_FILE— File could not be downloaded (check your URL)
Docs: https://docs.extend.ai/workflows/overview
Error Handling
SDKs raise typed exceptions for these errors (e.g., RateLimitError, UnauthorizedError). Error responses include a requestId — provide this when contacting support.
Docs: https://docs.extend.ai/api-reference/error-handling
Rate Limits
All rate limits are per-organization. If you receive 429 Too Many Requests, implement exponential backoff. SDK polling helpers handle backoff automatically; for other SDK calls, add your own retry logic.
Docs: https://docs.extend.ai/general/rate-limits (includes current limits by endpoint)
Evaluation Sets
Evaluation sets benchmark a processor (extractor, classifier, or splitter) against reviewed ground truth; they can also be run against workflows, which this section does not cover. Use the API for this rather than building a custom harness: the loop is four calls and the metrics are computed server-side with the same scoring Studio uses.
expectedOutput shape depends on the processor type:
- Extractor:
{ "value": { ...object conforming to the extractor schema... } }— nest undervalue, include every schema property. Easiest source: run the extractor on the file, correct the output, save it. - Classifier:
{ "id": "<classification id>", "type": "<classification name>" } - Splitter:
{ "splits": [{ "classificationId", "type", "startPage", "endPage" }] }
Run semantics: entity.version accepts "draft", "latest", or a published version like "1.0"; omitting entity runs the set’s default processor at draft. Status goes PENDING → PROCESSING → PROCESSED | FAILED | CANCELLED. No SDK has a polling helper for evaluation runs; poll every few seconds. Read metrics only when status is PROCESSED.
metrics is discriminated on type: EXTRACT has accuracy and fieldMetrics (field path → { countTotal, countPresent, countExpected, countAccurate, accuracy }, nested fields dot-joined); CLASSIFY has accuracy and classificationMetrics (per-class precision/recall/F1); SPLITTER has precision, recall, f1. The run returns aggregates only: per-document diffs, CSV export, custom matchers (fuzzy, LLM judge, vector), and field exclusion are Studio features.
Docs: https://docs.extend.ai/evaluation/creating-evaluation-sets and https://docs.extend.ai/evaluation/running-evaluation-sets (all four SDKs)

