Migration Guides2026-02-09

Migrating to API Version 2026-02-09

Welcome to the New API

The 2026-02-09 API version is a significant improvement designed to make your integration cleaner, more type-safe, and easier to maintain. We’ve listened to developer feedback and restructured the API around clearer resource types and better SDK support.

Why Migrate?

Here’s what you’ll get with the new API version:

Dedicated Endpoints with Typed Responses

The unified /processors and /processor_runs endpoints have been split into dedicated endpoints for each resource type:

ResourceOld EndpointsNew Endpoints
Extraction/processors + /processor_runs/extractors + /extract_runs + /extract
Classification/processors + /processor_runs/classifiers + /classify_runs + /classify
Splitting/processors + /processor_runs/splitters + /split_runs + /split

This means fully typed SDK responsesβ€”no more checking type fields or casting outputs:

Before
1const run = await client.processorRun.create({
2 processorId: "dp_abc123",
3 file: { fileUrl: "https://..." }
4 sync: true,
5});
6if (run.processorRun.type === "EXTRACT") {
7 const output = run.processorRun.output as ExtractOutput; // Manual cast
8}
After
1const result = await client.extract({
2 extractor: { id: "ex_abc123" },
3 file: { url: "https://..." }
4});
5console.log(result.output?.value); // Typed as ExtractOutput

TypeScript bonus: Define schemas with Zod for fully typed output values:

1import { ExtendClient, extendDate, extendCurrency } from "extend-ai";
2import { z } from "zod";
3
4const client = new ExtendClient({ token: "your-api-key" });
5
6const result = await client.extract({
7 config: {
8 schema: z.object({
9 invoice_number: z.string().nullable(),
10 invoice_date: extendDate(),
11 total: extendCurrency(),
12 }),
13 },
14 file: { url: "https://..." }
15});
16
17// TypeScript knows the exact shape!
18const output = result.output?.value;
19console.log(output.invoice_number); // string | null
20console.log(output.invoice_date); // string | null (ISO date)
21console.log(output.total.amount); // number | null
22console.log(output.total.iso_4217_currency_code); // string | null

Run Without Pre-Creating a Resource

Previously, you had to create and manage an extractor, classifier, or splitter resource before running. Now you can pass your config inlineβ€”perfect for managing schemas entirely in code.

Before: Required a processor resource
1const processor = await client.processor.create({
2 name: "Invoice Extractor",
3 type: "EXTRACT",
4 config: {
5 type: "EXTRACT",
6 schema: { type: "object", properties: { vendor: { type: "string" } } }
7 }
8});
9const run = await client.processorRun.create({
10 processorId: processor.processor.id,
11 file: { fileUrl: "https://..." }
12});
After: Config inline, no resource needed
1const run = await client.extractRuns.create({
2 config: {
3 schema: { type: "object", properties: { vendor: { type: "string" } } }
4 },
5 file: { url: "https://..." }
6});

Synchronous Endpoints

New synchronous endpoints let you process a file and get the result in a single requestβ€”no polling or webhooks needed. These are ideal for onboarding, testing, and low-volume use cases:

Sync EndpointAsync Equivalent
POST /extractPOST /extract_runs
POST /classifyPOST /classify_runs
POST /splitPOST /split_runs
POST /parse (updated)POST /parse_runs
POST /edit (updated)POST /edit_runs

1// Sync β€” returns the completed result directly
2const result = await client.extract({
3 extractor: { id: "ex_abc123" },
4 file: { url: "https://..." }
5});
6console.log(result.output?.value);

Sync endpoints are for testing and onboarding only. For production workloads, we recommend using the async *_runs endpoints with webhooks or polling, as they provide better reliability for large files and avoid timeout issues.

Polling Helpers

The async *_runs endpoints are the recommended approach for production. The SDK provides createAndPoll / create_and_poll methods that handle polling with exponential backoff:

1const result = await client.extractRuns.createAndPoll({
2 extractor: { id: "ex_abc123" },
3 file: { url: "https://..." }
4});
5// Returns when status is PROCESSED or FAILED
6console.log(result.output?.value);

Available for all run types: extractRuns, classifyRuns, splitRuns, parseRuns, editRuns, workflowRuns.

Workflow runs can take a long time. Complex workflows may run for hours. For workflows, consider using webhooks instead of polling unless you know the workflow will complete quickly.

Simplified Response Shapes

API responses are now cleaner and more consistent:

Single object responses are unwrapped. Instead of { "extractRun": { ... }, "success": true }, the API now returns the object directly:

Before
1{
2 "success": true,
3 "processorRun": {
4 "id": "dpr_abc123",
5 "status": "PROCESSED",
6 "output": { ... }
7 }
8}
After
1{
2 "id": "exr_abc123",
3 "status": "PROCESSED",
4 "output": { ... }
5}

List responses use a standardized format. All list endpoints now return { "object": "list", "data": [...] }:

Before
1{
2 "success": true,
3 "processorRuns": [ ... ],
4 "nextPageToken": "..."
5}
After
1{
2 "object": "list",
3 "data": [ ... ],
4 "nextPageToken": "..."
5}

SDK users: These changes are handled automatically by the SDK. You’ll access results directly (e.g., result.output instead of result.extractRun.output).

SDK Webhook Helpers

For event-driven processing, the SDK includes utilities for verifying signatures and parsing events with type-safe payloads:

1const event = client.webhooks.verifyAndParse(body, headers, secret);
2
3if (event.eventType === "extract_run.processed") {
4 console.log(event.payload.output); // Typed as ExtractRun
5}

See the Webhooks Migration guide for full details and examples in all languages.


Coming Soon

The following features will be added to the 2026-02-09 API version:

FeatureDescription
Webhook Endpoint ManagementCreate, update, list, and delete webhook endpoints via API
Workflow Management EndpointsFull CRUD operations for workflows via API (currently create-only)
Rate Limit HeadersRate limit info (X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset) in response headers

How to Upgrade

Step 1: Update to the New API Version

$npm install extend-ai@latest
$# or
$yarn add extend-ai@latest

The latest SDK automatically uses the 2026-02-09 API version.

Step 2: Migrate Endpoint by Endpoint

You don’t have to migrate everything at once. Start with the endpoints you use most and work through the detailed guides:

Processing Runs:

Resource Management:

Other Endpoints:

Step 3: Migrate Webhooks

If you use webhooks, follow the Webhooks Migration guide to update your webhook handlers. This includes:

  • New event type names (e.g., processor_run.processed β†’ extract_run.processed)
  • New payload structures with typed responses
  • New SDK helpers for signature verification

Need Help?

  • Questions? Contact our support team at support@extend.app
  • Found a bug? Let us know and we’ll fix it ASAP
  • Feedback on the new API? We’d love to hear itβ€”reach out on Slack!

Migration Guides

Jump to the specific guide for the endpoints you use:

GuideMigrating FromMigrating To
Extract Runs/processor_runs/extract_runs + /extract
Classify Runs/processor_runs/classify_runs + /classify
Split Runs/processor_runs/split_runs + /split
Parse Runs/parse, /parse/async/parse_runs + /parse
Edit Runs/edit, /edit/async/edit_runs + /edit
Extractors/processors/extractors
Classifiers/processors/classifiers
Splitters/processors/splitters
Files/files/files (breaking changes)
Evaluation Setsevaluation endpointsUpdated evaluation endpoints
Workflow Runs/workflow_runs/workflow_runs (breaking changes)
Webhooksprocessor_run.* eventsextract_run.*, classify_run.*, etc.