Pipelines
Save, version, and reuse extraction configurations.
A pipeline bundles OCR model, LLM model, JSON Schema, and extraction options for reuse across documents. Pipelines are tenant-scoped, identified by oppl_… ids, and versioned on each update. In-flight and completed jobs keep their admit-time snapshot when you patch a pipeline later.
Field definitions live in the Pipelines API reference.
List pipelines
GET /pipelines returns active (non-deleted) pipelines for your organization, newest updates first.
curl -s 'https://api.openparser.dev/pipelines' \
-H 'Authorization: Bearer YOUR_API_KEY'openparser pipelines list --jsonconst { items } = await client.pipelines.list();pipelines = client.pipelines.list()Get a pipeline
GET /pipelines/{id} returns one active pipeline including its current version. Deleted, missing, and cross-tenant ids return 404 pipeline_not_found.
curl -s 'https://api.openparser.dev/pipelines/oppl_...' \
-H 'Authorization: Bearer YOUR_API_KEY'openparser pipelines get oppl_... --jsonconst pipeline = await client.pipelines.get('oppl_...');pipeline = client.pipelines.get("oppl_...")Create a pipeline
POST /pipelines persists a validated extraction configuration. Names and slugs must be unique within your organization; duplicates return 409 pipeline_name_conflict.
curl -X POST 'https://api.openparser.dev/pipelines' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"name": "Invoice fields",
"slug": "invoice-fields",
"ocr_model": "paddleocr-vl-1.6",
"llm_model": "openai/gpt-6-luna",
"schema": {
"type": "object",
"properties": {
"invoice_number": { "type": "string" }
},
"required": ["invoice_number"],
"additionalProperties": false
}
}'openparser pipelines create \
--name "Invoice fields" \
--slug invoice-fields \
--ocr-model paddleocr-vl-1.6 \
--llm-model openai/gpt-6-luna \
--schema-json '{"type":"object","properties":{"invoice_number":{"type":"string"}},"required":["invoice_number"],"additionalProperties":false}'const pipeline = await client.pipelines.create({
name: 'Invoice fields',
slug: 'invoice-fields',
ocr_model: 'paddleocr-vl-1.6',
llm_model: 'openai/gpt-6-luna',
schema: {
type: 'object',
properties: {
invoice_number: { type: 'string' },
},
required: ['invoice_number'],
additionalProperties: false,
},
});pipeline = client.pipelines.create({
"name": "Invoice fields",
"slug": "invoice-fields",
"ocr_model": "paddleocr-vl-1.6",
"llm_model": "openai/gpt-6-luna",
"schema": {
"type": "object",
"properties": {
"invoice_number": {"type": "string"},
},
"required": ["invoice_number"],
"additionalProperties": False,
},
})Update a pipeline
PATCH /pipelines/{id} merges one or more fields, re-validates the effective configuration, and increments version. Send only the fields you want to change.
curl -X PATCH 'https://api.openparser.dev/pipelines/oppl_...' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{"name": "Invoice fields v2"}'openparser pipelines update oppl_... --name "Invoice fields v2" --jsonconst updated = await client.pipelines.update('oppl_...', {
name: 'Invoice fields v2',
});updated = client.pipelines.update(
"oppl_...",
{"name": "Invoice fields v2"},
)Delete a pipeline
DELETE /pipelines/{id} soft-deletes the pipeline. New extract admissions with that id return 404 pipeline_not_found; historical jobs retain their snapshotted configuration.
curl -X DELETE 'https://api.openparser.dev/pipelines/oppl_...' \
-H 'Authorization: Bearer YOUR_API_KEY'openparser pipelines delete oppl_... --jsonawait client.pipelines.delete('oppl_...');client.pipelines.delete("oppl_...")Use a pipeline on extract
Pass pipeline_id in extract admission instead of inline ocr_model, llm_model, and schema. The two shapes are mutually exclusive. OpenParser records the pipeline version at admit time.
curl -X POST 'https://api.openparser.dev/extract/async' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H "Idempotency-Key: $(uuidgen 2>/dev/null || openssl rand -hex 16)" \
-F 'request={"pipeline_id":"oppl_..."};type=application/json' \
-F 'file=@./document.pdf'openparser extract async ./document.pdf --pipeline-id oppl_... --jsonconst accepted = await client.extract.async(
{ pipeline_id: 'oppl_...' },
file,
);from pathlib import Path
accepted = client.extract.async_(
{"pipeline_id": "oppl_..."},
file=Path("document.pdf"),
)You can also set pipeline_id on individual items in POST /extract/batch.