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

# Publishing Processors

> Publish a new major or minor version of an extractor, classifier, or splitter.

Every processor has one editable **draft** and a history of immutable **published versions**. All edits, whether made in Studio or with `extractors.update` / `classifiers.update` / `splitters.update`, land on the draft. Publishing snapshots the draft into a new version string (`"1.0"`, `"1.1"`, `"2.0"`) that never changes afterwards.

Publishing does not affect anything already using the processor. A workflow step or API call that references `"1.0"` keeps running `"1.0"`; only references that say `"latest"` pick up the new version. That is what lets you iterate on the draft freely and promote a version only when your [evaluation set](/evaluation/running-evaluation-sets) says it is ready.

## Major or minor?

The release type decides how the version number increments. Nothing else about the version differs; the distinction is a signal to the people and workflows consuming the processor.

| Publish as                | When                                                                                                                                                                                                                                  | Example                                                                                  |
| ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| **Minor** (`1.0` → `1.1`) | The change does not alter the shape of the output. Field description or prompt wording tweaks, rule adjustments, a base processor change. Safe for consumers pinned to the previous minor to adopt without code changes.              | Rewording the description of `invoice_total` so the model stops picking up the subtotal. |
| **Major** (`1.1` → `2.0`) | The change alters the output shape or how the processor interacts with a workflow. Adding, removing, renaming, or retyping schema fields; changing classification types; changing split identifiers. Downstream code must be updated. | Adding a required `line_items` array to the schema.                                      |

## Via the API

### Update the draft

Make your configuration change on the draft first. The `update` endpoints accept the full `config` for the processor type and write it to the draft; see [Extraction configuration](/extraction/configuration), [Classification configuration](/classification/configuration), or [Splitting configuration](/splitting/configuration) for the config shape. Run your [evaluation set](/evaluation/running-evaluation-sets) against `"draft"` before publishing.

### Publish a version

Publish snapshots the current draft. `releaseType` is `"major"` or `"minor"`; `description` is free text that shows in the version history and is worth writing for whoever reads the history later.

#### Python

```python
from extend_ai import Extend

client = Extend()

published = client.extractor_versions.create(
    "ex_Xj8mK2pL9nR4vT7qY5wZ",
    release_type="minor",
    description="Clarify invoice_total description to exclude subtotals",
)
print(published.version)  # "1.1"
```

#### TypeScript

```typescript
import { ExtendClient } from "extend-ai";

const client = new ExtendClient();

const published = await client.extractorVersions.create("ex_Xj8mK2pL9nR4vT7qY5wZ", {
  releaseType: "minor",
  description: "Clarify invoice_total description to exclude subtotals",
});
console.log(published.version); // "1.1"
```

#### Java

```java
import ai.extend.ExtendClient;
import ai.extend.resources.extractorversions.requests.ExtractorVersionsCreateRequest;
import ai.extend.types.ExtractorVersion;
import ai.extend.types.ReleaseType;

ExtendClient client = ExtendClient.builder().build();

ExtractorVersion published = client.extractorVersions().create(
    "ex_Xj8mK2pL9nR4vT7qY5wZ",
    ExtractorVersionsCreateRequest.builder()
        .releaseType(ReleaseType.MINOR)
        .description("Clarify invoice_total description to exclude subtotals")
        .build());
System.out.println(published.getVersion()); // "1.1"
```

#### Go

```go
package main

import (
	"context"
	"fmt"
	"log"

	extend "github.com/extend-hq/extend-go-sdk"
	client "github.com/extend-hq/extend-go-sdk/client"
)

func main() {
	c := client.NewClient()
	ctx := context.Background()

	published, err := c.ExtractorVersions.Create(ctx, "ex_Xj8mK2pL9nR4vT7qY5wZ",
		&extend.ExtractorVersionsCreateRequest{
			ReleaseType: extend.ReleaseTypeMinor,
			Description: extend.String("Clarify invoice_total description to exclude subtotals"),
		})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(published.Version) // "1.1"
}
```

The same call exists for the other processor types: `classifierVersions.create` (`classifier_versions.create`) and `splitterVersions.create` (`splitter_versions.create`), with the same `releaseType` and `description` fields.

### Reference the version

Anywhere a processor is referenced you can pass a `version`. The three special forms:

| `version`             | Resolves to                                                                |
| --------------------- | -------------------------------------------------------------------------- |
| omitted or `"latest"` | The most recent published version. If nothing is published yet, the draft. |
| `"draft"`             | The current draft. Development only.                                       |
| `"1.1"`               | Exactly that published version. Pin this in production.                    |

In a standalone run:

#### Python

```python
result = client.extract(
    file={"url": "https://example.com/invoice.pdf"},
    extractor={"id": "ex_Xj8mK2pL9nR4vT7qY5wZ", "version": "1.1"},
)
```

#### TypeScript

```typescript
const result = await client.extract({
  file: { url: "https://example.com/invoice.pdf" },
  extractor: { id: "ex_Xj8mK2pL9nR4vT7qY5wZ", version: "1.1" },
});
```

#### Java

```java
import ai.extend.requests.ExtractRequest;
import ai.extend.types.ExtractRequestExtractor;
import ai.extend.types.ExtractRequestFile;
import ai.extend.types.ExtractRun;
import ai.extend.types.FileFromUrl;

ExtractRun result = client.extract(ExtractRequest.builder()
    .file(ExtractRequestFile.of(FileFromUrl.builder().url("https://example.com/invoice.pdf").build()))
    .extractor(ExtractRequestExtractor.builder()
        .id("ex_Xj8mK2pL9nR4vT7qY5wZ")
        .version("1.1")
        .build())
    .build());
```

#### Go

```go
result, err := c.Extract(ctx, &extend.ExtractRequest{
	File: &extend.ExtractRequestFile{
		FileFromURL: &extend.FileFromURL{URL: "https://example.com/invoice.pdf"},
	},
	Extractor: &extend.ExtractRequestExtractor{
		ID:      "ex_Xj8mK2pL9nR4vT7qY5wZ",
		Version: extend.String("1.1"),
	},
})
if err != nil {
	log.Fatal(err)
}
```

In a workflow step definition, the `extractor` reference must include an explicit `version`:

```json
{
  "name": "extract",
  "type": "EXTRACT",
  "config": {
    "extractor": { "id": "ex_Xj8mK2pL9nR4vT7qY5wZ", "version": "1.1" }
  },
  "next": [{ "step": "review" }]
}
```

A deployed workflow version freezes this reference. Choose `"1.1"` for reproducibility or `"latest"` to let the workflow adopt future publishes automatically. See [Configuring Workflows via API](/workflows/configuring-workflows) and [Workflow Versioning](/workflows/workflow-versioning).

### List versions

`list` returns versions newest-first with `draft` at the top. Use it to find the version string to pin, or to check whether the draft has unpublished changes.

#### Python

```python
versions = client.extractor_versions.list("ex_Xj8mK2pL9nR4vT7qY5wZ")
for v in versions.data:
    print(v.version, v.description or "")
```

#### TypeScript

```typescript
const versions = await client.extractorVersions.list("ex_Xj8mK2pL9nR4vT7qY5wZ");
for (const v of versions.data) {
  console.log(v.version, v.description ?? "");
}
```

#### Java

```java
import ai.extend.resources.extractorversions.types.ExtractorVersionsListResponse;

ExtractorVersionsListResponse versions = client.extractorVersions().list("ex_Xj8mK2pL9nR4vT7qY5wZ");
versions.getData().forEach(v ->
    System.out.println(v.getVersion() + " " + v.getDescription().orElse("")));
```

#### Go

```go
versions, err := c.ExtractorVersions.List(ctx, "ex_Xj8mK2pL9nR4vT7qY5wZ",
	&extend.ExtractorVersionsListRequest{})
if err != nil {
	log.Fatal(err)
}
for _, v := range versions.Data {
	description := ""
	if v.Description != nil {
		description = *v.Description
	}
	fmt.Println(v.Version, description)
}
```

## Via Extend Studio

From the processor page in Studio, you can publish new versions of your processor, which can then be selected and used in one or more workflows deployed on Extend.

![Extractor page in Studio with the Publish button and the "Unpublished changes" indicator](/_fern-img/e7a92f81dcb0ea81631bde81b93969e05a31c4bb78e1268b46f52fe163052c6d.webp)

When you save changes to a processor, they update the draft. You can make as many changes as you want to the draft before publishing. Once you publish, the draft changes are rolled into the new version and the draft goes back to having no "Unpublished changes".

### Minor version

To publish a minor version, click the "Publish" button and select the "Minor" radio option:

![Publish dialog with the Minor release type selected](/_fern-img/d0efbfd8b914569be63b787ec8d5bb74fcfa94327f8cc9b28a6a90bfdee9de0f.webp)

### Major version

To publish a major version, click the "Publish" button and select the "Major" radio option:

![Publish dialog with the Major release type selected](/_fern-img/bef61fe949d5ea701a2b70911ecd92f803599365825a3cac090d70a59b8b03bc.webp)

### Viewing published versions

Once a version is published, it cannot be updated and is viewable in read-only mode.

Select a published version on the processor Overview tab to see its details and the configuration it was published with:

![Processor Overview tab showing the version selector and a published version's read-only configuration](/_fern-img/4a09a54bb8a38dbc2f4085773f86abd22608ec1884ffa24bacc67e2aa01a24aa.webp)

## Reference

* [Create Extractor Version](/api-reference/endpoints/extract/create-extractor-version), [Create Classifier Version](/api-reference/endpoints/classify/create-classifier-version), [Create Splitter Version](/api-reference/endpoints/split/create-splitter-version), [List Extractor Versions](/api-reference/endpoints/extract/list-extractor-versions)
* [Processors](/evaluation/processors): what a saved processor is and when to use one
* [Running Evaluation Sets](/evaluation/running-evaluation-sets): gate a publish on accuracy
* [Workflow Versioning](/workflows/workflow-versioning): the parallel concept for workflows
* [Create a Workflow](/workflows/overview): use a published processor in a pipeline