API Reference

Complete API endpoint documentation.

Base URL

Text
https://api.smole.tech

Interactive Docs: Explore and test all endpoints directly in the Swagger API Reference.

Authentication

Include your API key in the X-API-Key header:

HTTP
X-API-Key: ak_your_api_key

Schema Endpoints

Manage your extraction schemas. See Schemas for examples of creating and using schemas.

POST/api/schemas

Create a new schema manually with a JSON Schema definition

POST/api/schemas/generate

Generate a schema using AI from field definitions (async)

GET/api/schemas

List all your schemas

GET/api/schemas/:id

Get a specific schema

PUT/api/schemas/:id

Update a schema

DELETE/api/schemas/:id

Delete a schema

Workflow Endpoints

A workflow is a reusable way to process documents: it references one schema and adds its own preparation settings. Workflows belong to a workspace; get your workspace ID from GET /v1/workspaces. Paths below start with /v1/workspaces/:workspaceId.

POST/workflows

Create a workflow. Returns it with version 1, which can run straight away

GET/workflows

List workflows, newest first. Query: limit (1–100), cursor (the previous page's nextCursor), archived

GET/workflows/:workflowId

Get a workflow

PUT/workflows/:workflowId

Save a workflow. Body: { expectedRevision, input }

POST/workflows/:workflowId/archive

Archive a workflow. Body: { expectedRevision }

GET/workflows/:workflowId/versions

List a workflow's versions. Query: limit, afterVersion

GET/workflow-versions/:versionId

Get one workflow version

Workflow body

POST sends this object; PUT sends it as input. Every key is required and unknown keys are rejected. schemaId is a built-in schema or one of yours, and maxPages is null or 1 to 10,000.

JSON
{
  "title": "Invoices (scans)",
  "description": "Scanned supplier invoices",
  "schemaId": "123e4567-e89b-12d3-a456-426614174000",
  "definition": {
    "contractVersion": 2,
    "preparation": {
      "forceOcr": true,
      "preserveTables": true,
      "preserveLinks": true,
      "maxPages": null
    }
  }
}

Saving is publishing. A save that changes the schema or the preparation settings creates the next version (latestVersion, latestVersionId); a new title or description does not. Each save, and archiving an active workflow, increases revision, so send the revision you last read as expectedRevision. Versions are immutable, and a run keeps the version it started with, even if the workflow is edited or archived while it runs.

Webhook Endpoints

Webhooks send a signed event to your endpoint each time a run of a workflow finishes. See Webhooks for events, signatures and retries. Paths below start with /v1/workspaces/:workspaceId.

GET/integrations/capabilities

The integration kinds you can set up, for example { "kinds": ["webhook"] }

GET/workflows/:workflowId/bindings

List a workflow's webhooks (at most 5)

POST/workflows/:workflowId/bindings

Add a webhook. Body: { kind: "webhook", name, config: { url, events, includeResult } }. Returns { binding, secret }; the secret is never returned again

GET/bindings/:bindingId

Get a webhook. config.secretHint shows the secret's last characters

PATCH/bindings/:bindingId

Change a webhook. Body: { expectedRevision, input } with the full input

DELETE/bindings/:bindingId

Delete a webhook and cancel its queued deliveries

POST/bindings/:bindingId/pause

Pause sending. Events of finished runs wait for up to 7 days

POST/bindings/:bindingId/resume

Resume sending and clear the failure count

POST/bindings/:bindingId/test

Queue a free ping event

POST/bindings/:bindingId/rotate-secret

Returns { binding, secret } with a new secret, once. The old one keeps working for 24 hours

GET/bindings/:bindingId/deliveries

Deliveries, newest first. Query: state (failed lists the dead letters), limit (1–100), cursor

POST/deliveries/:deliveryId/redeliver

Send a delivered or failed event again, with the same ID and body. It never processes the document again

Pipeline Endpoints

Process documents through the extraction pipeline. See Configuration for all available parameters.

POST/api/pipeline/file

Upload a file and extract data using a schema or a workflow

POST/api/pipeline/url

Process a document from a URL using a schema or a workflow

POST/api/pipeline/base64

Process a base64-encoded document using a schema or a workflow

GET/api/pipeline

List your pipeline jobs, newest first. Add ?workflowId= for one workflow's runs

GET/api/pipeline/:id

Get pipeline job status and result

Documents and billing

Each submitted file is one document, whatever its page count, and uses 1 document unit of your plan. Conversion, OCR and extraction in one pipeline count together. Usage is reserved while a job runs, counted once when it succeeds and released if it fails or is cancelled. After a client timeout, check the existing job before submitting again to avoid duplicate work.

processingMode is optional and accepted for compatibility: both values, normal and fast, are processed the same way at the same price. processingQuoteId is optional and no longer needed. GET /api/users/me/usage reports document counts, allowance usage and pending reservations.

Run a workflow

Send exactly one of schemaId or workflowId. A workflow run uses the workflow's latest version, and that version supplies the schema and the preparation settings. The Idempotency-Key header works as for any run.

Terminal
curl -X POST https://api.smole.tech/api/pipeline/file \
  -H "X-API-Key: ak_your_api_key" \
  -F "file=@invoice.pdf" \
  -F "workflowId=your_workflow_id"

# The workflow's runs, newest first
curl "https://api.smole.tech/api/pipeline?workflowId=your_workflow_id" \
  -H "X-API-Key: ak_your_api_key"

Processing options cannot be sent with workflowId: the file route rejects quality, extractImages, preserveLinks, preserveTables, maxPages, ocrEnabled, ocrForce and ocrLanguages, and the URL and base64 routes reject conversionOptions and extractionChunking, each with 400 PIPELINE_VALIDATION_ERROR. The list filter returns an empty list for an unknown workflow and cannot be combined with ids.

A workflow run is a normal pipeline job and is billed like one: it uses 1 document unit, and failed runs, including RESULT_SCHEMA_INVALID, and cancelled runs are not charged: their reservation is released. Creating, editing, viewing and exporting workflows is free.

API Key Scopes

Workflow and webhook routes need a file key created for the workspace in Account → API keys, with the scopes the request needs. Processing keys work on the /api routes only.

ScopeAllows
workflows:writeCreate, edit and archive workflows
runs:submitSubmit documents with POST /api/pipeline/{file,url,base64}, with a schemaId or a workflowId
documents:readRead workflows, their versions and runs, and list runs with GET /api/pipeline
integrations:manageAdd, change, test and delete a workflow's webhooks, list their deliveries and redeliver

User Endpoints

GET/api/users/me/usage

Get current usage statistics

Response Format

Pipeline job response:

JSON
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "completed",
  "processingMode": "normal",
  "schemaId": "123e4567-e89b-12d3-a456-426614174000",
  "schemaVersion": 3,
  "workflowId": "9b2f6a1e-4c1d-4f7a-9e3b-2d5c8a7f1e04",
  "workflowVersionId": "0c8e4d2a-7b5f-4e19-8a63-1f9d2c4b6e57",
  "workflowVersion": 2,
  "steps": [
    { "name": "conversion", "status": "completed" },
    { "name": "extraction", "status": "completed" }
  ],
  "result": {
    "invoiceNumber": "INV-12345",
    "total": 150.00,
    "date": "2024-01-15",
    "purchaseOrder": null
  },
  "totalCostCents": 5,
  "createdAt": "2024-01-15T10:00:00Z",
  "completedAt": "2024-01-15T10:00:15Z"
}

Fields that couldn't be found in the document are returned as null. See Missing Data and Null Values for details.

schemaVersion is the schema version the run used. workflowId, workflowVersionId and workflowVersion identify the workflow version a run pinned, and are null for runs with a schemaId. Items of GET /api/pipeline carry these fields too. A failed run, from GET /api/pipeline/:id or the list, also has error, errorCode, errorStage (conversion or extraction) and errorRetryable.

Error Codes

Errors from the /api route handlers use the first body below, sometimes with details. An unknown, disabled or expired API key, or a missing sign-in, returns 401 with only { message }. The /v1 workflow routes, and permission errors on every route, /api included, use the second body, as does 401 INVALID_API_KEY for a key that is not bound to the workspace:

JSON
{ "error": "WORKFLOW_ARCHIVED", "message": "This workflow is archived and cannot run" }

{
  "code": "WORKFLOW_REVISION_CONFLICT",
  "message": "This workflow changed. Reload it before saving.",
  "retryAction": "change_input",
  "requestId": "…"
}

A key without the scope a route needs gets 403 PERMISSION_DENIED in the second body.

WORKFLOW_NOT_FOUND404

The workflow does not exist in this workspace. A run also returns it for a workflow you cannot use.

WORKFLOW_ARCHIVED409

The workflow is archived. It can no longer be edited or run.

WORKFLOW_REVISION_CONFLICT409

expectedRevision is not the workflow's current revision. Reload it and save again.

INVALID_WORKFLOW400

The workflow body is invalid: a missing or unknown key, an empty title, or maxPages outside 1 to 10,000.

SCHEMA_NOT_FOUND404

The schema does not exist, or it is neither a built-in schema nor one of yours.

SCHEMA_NOT_READY409

The schema is not ready (still generating, or generation failed): saving a workflow with it, or starting a run with its schemaId or with a workflow that uses it.

SCHEMA_IN_USE409

DELETE /api/schemas/:id while an active workflow uses the schema. Archive the workflow first.

PIPELINE_VALIDATION_ERROR400

Both or neither of schemaId and workflowId, processing options sent with workflowId, or ids combined with workflowId.

WORKFLOW_VERSION_NOT_FOUND404

The workflow version does not exist in this workspace.

INVALID_REQUEST400

A workflow request is malformed: a PUT body that is not exactly { expectedRevision, input }, an archive body that is not exactly { expectedRevision }, or an invalid query.

INVALID_REVISION400

expectedRevision is not a positive integer.

CONTRACT_VERSION_UNSUPPORTED400

definition.contractVersion is not 2.

INVALID_CURSOR400

The list cursor was not returned by this list.

DESTINATION_URL_NOT_ALLOWED400

The webhook URL is not public HTTPS on port 443, has credentials, or resolves to a local or private address.

INVALID_BINDING400

The webhook body is invalid: a missing or unknown key, an empty name, or no events.

BINDING_NOT_FOUND404

The webhook does not exist in this workspace.

DELIVERY_NOT_FOUND404

The delivery does not exist. Finished deliveries are kept for 30 days.

BINDING_LIMIT_REACHED409

A limit is reached: the workflow already has 5 outputs (webhooks and Google Sheets together) or 5 sources, the Google Sheet already serves 10 workflows, or the workspace already holds 1,000 sources and outputs.

BINDING_REVISION_CONFLICT409

expectedRevision is not the webhook's current revision, or another rotation won. Reload it and try again.

BINDING_TEST_IN_PROGRESS409

A test ping of this webhook is still on its way.

DELIVERY_NOT_REDELIVERABLE409

The delivery is still queued or being sent. Only delivered or failed deliveries can be sent again.

INTEGRATION_DISABLED503

This kind of integration is not available for this workspace.