Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.anyformat.ai/llms.txt

Use this file to discover all available pages before exploring further.

The hand-written TypeScript SDK for anyformat. The wire types and the low-level HTTP client are generated from the API’s OpenAPI spec with Hey API; the ergonomic layer (Anyformat, Schema, WorkflowBuilder, Result) is hand-written and mirrors the Python SDK.

Installation

Requires Node 18+.
npm install @anyformat/sdk
The package ships ESM + CJS bundles and TypeScript types.

Authentication

Pass the API key to the Anyformat constructor, or read it from the environment.
import { Anyformat } from "@anyformat/sdk";

// Explicit
const af = new Anyformat({ apiKey: "af_..." });

// Or from the environment (Node)
const af2 = new Anyformat({ apiKey: process.env.ANYFORMAT_API_KEY! });
Override the base URL with baseUrl if you’re running against a non-production deploy. See Authentication for how to mint an API key.

Basic usage

Full flow: build a workflow with a fluent builder, submit a document, await the typed result.
import { Anyformat, Schema } from "@anyformat/sdk";

const af = new Anyformat({ apiKey: process.env.ANYFORMAT_API_KEY! });
const file: File = /* a File with .name set, e.g. new File([bytes], "invoice.pdf") */;

const workflow = await af
  .workflow("Invoice Processor", "Extract invoice header and totals")
  .parse()
  .extract([
    Schema.string("invoice_number", "The unique invoice identifier"),
    Schema.float("total_amount",    "Total invoice amount"),
    Schema.date("issue_date",       "Date when the invoice was issued"),
  ])
  .create();             // persists the workflow → returns a Workflow handle

const run = await workflow.run(file);   // submits the document
const result = await run.wait();        // polls /results/ until 200

console.log(result.field("invoice_number")?.value);
console.log(result.field("total_amount")?.value);
The TS SDK splits “create workflow” from “submit document”, mirroring the Python SDK. create() returns a Workflow handle whose run(file) reuses the existing workflow id — so processing N documents through the same workflow costs one POST /v2/workflows/ plus N POST /v2/workflows/{id}/run/, not N create+run pairs.

wait options

wait defaults: 300s overall timeout, 3s poll interval. Override either:
const result = await run.wait({ timeoutMs: 180_000, pollMs: 3_000 });
SDKTimeout is thrown if the overall deadline expires before the run completes. The internal poll handles 412 (still processing) automatically.

Builder methods

All node types in the typed graph are exposed as fluent methods. parse is required; the others are optional and can be chained in any topology the API allows.
MethodWhat it addsNotes
.parse(opts?)The required parse nodeopts = { mode: "standard" | "agentic", promptHint?, figureEnhancement? }
.classify(categories, opts?)A classify nodeCategories from ClassifyCategory objects (id, name, description)
.split(rules, opts?)A splitter nodeopts.routeFrom wires which classify branch fans out
.extract(fields, opts?)An extract nodeopts.branch is required after .classify() / .split(); build fields with Schema.*
.validate(rules, opts?)A validate nodeAttaches to the most recent extract (or opts.branch)
.build()Same shape, no network callReturns a WorkflowCreateRequest
.create()Persists the workflowReturns a Workflow handle (id + .run(...))
The Workflow handle returned by .create() has one method:
MethodWhat it doesNotes
.run(file, opts?)Submits a document against the existing workflow idopts.text to submit raw text instead of a file; pass null as the file
Workflow.run returns a Run; Run.wait(opts?) returns a Result once processing finishes.

Reading results

const result = await run.wait();

// Scalar fields, for linear workflows (single untagged extraction)
const inv = result.field("invoice_number");
console.log(inv?.value, inv?.confidence, inv?.evidence);

// Anything else — nested objects, split workflows, classifications:
// read result.raw, the validated wire envelope.
const markdown = result.raw.parse?.markdown;
for (const extraction of result.extractions) {
  for (const [name, field] of Object.entries(extraction.fields)) {
    console.log(name, field);
  }
}
See Response formats for the full shape of every section.

Error handling

The SDK exports typed error classes:
import {
  AnyformatError,   // base class
  APIError,         // every HTTP failure that isn't a typed subclass
  BadRequest,       // 400 — validation error, bad request body
  Unauthorized,     // 401 — invalid or missing API key
  Forbidden,        // 403 — disallowed by the server
  NotFound,         // 404 — workflow / file / webhook does not exist
  RateLimited,      // 429 — slow down
  ServerError,      // 5xx — internal anyformat error
  SDKTimeout,       // local timeout — wait() exceeded timeoutMs
  WorkflowBuilderError, // builder-API misuse, e.g. .extract() before .parse()
} from "@anyformat/sdk";

try {
  const workflow = await af.workflow("…").parse().extract([/* … */]).create();
  const run = await workflow.run(file);
  const result = await run.wait();
} catch (err) {
  if (err instanceof RateLimited) {
    // back off, retry
  } else if (err instanceof NotFound) {
    // workflow or file is gone
  } else if (err instanceof APIError) {
    console.error(`HTTP ${err.status}`, err.body);
  } else if (err instanceof SDKTimeout) {
    // polling deadline exceeded
  } else {
    throw err;
  }
}
Wire-format error codes (e.g. EXTRACTION_FAILED, RATE_LIMITED) are documented at Errors. The APIError.body field holds the parsed JSON body the server returned.

Webhooks (not on the SDK surface yet)

Anyformat doesn’t expose webhook endpoints directly today. Until it does, register and delete webhooks with fetch or the generated low-level client:
const res = await fetch("https://api.anyformat.ai/v2/webhooks/", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.ANYFORMAT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://your-server.com/hook",
    events: ["extraction.completed"],
  }),
});
const webhook = await res.json();
// webhook.secret is only returned once — store it.
See Webhooks for the payload shape and signature verification.
  • npmnpm install @anyformat/sdk
  • Python SDK — the same fluent shape in Python
  • Coding assistant — let Claude drive anyformat from your editor