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

# API quickstart

> Create a workflow, run a document through it, and read the extracted values with curl, TypeScript, or Python.

Three steps: create a workflow, run a document through it, read the values. The invoice extractor below pulls `invoice_number`, `total_amount`, and `issue_date`.

<Note>
  Prefer to click? The [Quickstart](/guides/quickstart) builds the same workflow at [app.anyformat.ai](https://app.anyformat.ai) with no code. Building your first workflow there is faster, and you can call it from the API afterwards with its workflow ID.
</Note>

## Before you start

Get an API key from [app.anyformat.ai/api-key](https://app.anyformat.ai/api-key). The snippets below read it from the environment. Both SDKs also take the key as a constructor argument. The [Python SDK page](/api-reference-v3/sdks/python) carries the Python version pin.

<CodeGroup>
  ```bash curl theme={null}
  export ANYFORMAT_API_KEY="your_api_key_here"
  ```

  ```bash TypeScript theme={null}
  npm install @anyformat/sdk   # Node 18+
  export ANYFORMAT_API_KEY="your_api_key_here"
  ```

  ```bash Python theme={null}
  pip install anyformat        # Python 3.13
  export ANYFORMAT_API_KEY="your_api_key_here"
  ```
</CodeGroup>

## 1. Create a workflow

A workflow is a [typed graph](/concepts/workflows) of nodes. The smallest extraction shape is a `parse` node feeding an `extract` node: two nodes, one edge. Both SDKs expose a fluent builder over that same graph. [Nodes](/guides/nodes/overview) covers the other node types, including Classify and Split.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST 'https://api.anyformat.ai/v3/workflows/' \
    -H 'Content-Type: application/json' \
    -H "Authorization: Bearer $ANYFORMAT_API_KEY" \
    -d '{
    "name": "Invoice Processing",
    "description": "Extract key data from invoices",
    "nodes": [
      {"id": "parse_1", "type": "parse"},
      {
        "id": "extract_1",
        "type": "extract",
        "extraction_schema": {"fields": [
          {"name": "invoice_number", "data_type": "string",
           "description": "The unique invoice identifier"},
          {"name": "total_amount", "data_type": "float",
           "description": "Total invoice amount"},
          {"name": "issue_date", "data_type": "date",
           "description": "Date when the invoice was issued"}
        ]}
      }
    ],
    "edges": [{"source": "parse_1", "target": "extract_1"}]
  }'
  ```

  ```typescript TypeScript theme={null}
  import { Anyformat, Schema } from "@anyformat/sdk";

  const af = new Anyformat({ apiKey: process.env.ANYFORMAT_API_KEY! });

  // .create() persists the workflow and returns its id.
  const workflowId = await af
    .workflow("Invoice Processing", "Extract key data from invoices")
    .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();

  console.log(`Created workflow: ${workflowId}`);
  ```

  ```python Python theme={null}
  import os
  from anyformat.sdk import Client
  from anyformat.workflow import Schema

  client = Client(api_key=os.environ["ANYFORMAT_API_KEY"])

  workflow = (
      client.workflow("Invoice Processing")
      .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 and returns a Workflow handle
  )

  print(f"Created workflow: {workflow.id}")
  ```
</CodeGroup>

Keep the workflow ID. Over HTTP it arrives as `id`, alongside the name, description, and timestamps:

```json highlight={2} theme={null}
{
  "id": "550e8400-e29b-41d4-a716-446655440000",
  "name": "Invoice Processing",
  "…": "…"
}
```

## 2. Run a document

[Upload and run](/api-reference-v3/workflows/upload-and-run) uploads the file and starts a run in one call. Replace `WORKFLOW_ID` with the ID from step 1.

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST 'https://api.anyformat.ai/v3/workflows/WORKFLOW_ID/upload/run/' \
    -H "Authorization: Bearer $ANYFORMAT_API_KEY" \
    -F 'files=@invoice.pdf'
  ```

  ```typescript TypeScript theme={null}
  // The TS SDK collapses submit and poll into one .run(file).wait() chain.
  // Build the same shape, or look the workflow up by id with the low-level client.
  // `file` must be a File with .name set.
  const file = new File([bytes], "invoice.pdf");

  const result = await af
    .workflow("Invoice Processing", "Extract key data from invoices")
    .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"),
    ])
    .run(file)
    .wait();  // continues into step 3
  ```

  ```python Python theme={null}
  run = workflow.run("invoice.pdf")  # Path | str | bytes
  ```
</CodeGroup>

The `202` response carries the `run_id`. Keep it to poll for results. `status: "queued"` means the run was accepted, not that extraction has finished.

```json highlight={2,5} theme={null}
{
  "run_id": "069dcc2c-e14c-7606-8000-2ee4fb17b4f9",
  "document_packet_id": "069dcc2c-e14c-7606-8000-2ee4fb17b4e1",
  "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
  "status": "queued"
}
```

## 3. Read the values

Poll [the run](/api-reference-v3/runs/get). It always returns **200**. `results` is `null` until `status` is `processed`, and then the results envelope arrives inline on the same read. Stop polling when `status` is `processed`, `error`, or `cancelled`.

<CodeGroup>
  ```bash curl theme={null}
  curl -H "Authorization: Bearer $ANYFORMAT_API_KEY" \
    "https://api.anyformat.ai/v3/runs/RUN_ID/"
  ```

  ```typescript TypeScript theme={null}
  // `result` was awaited in step 2.
  console.log(result.field("invoice_number")?.value);
  console.log(result.field("total_amount")?.value);
  console.log(result.field("issue_date")?.value);
  ```

  ```python Python theme={null}
  result = run.wait()
  print(result.fields["invoice_number"].value)
  print(result.fields["total_amount"].value)
  print(result.fields["issue_date"].value)
  ```
</CodeGroup>

A finished run reports `status: "processed"`, and each extracted field carries a `value` and a `confidence`:

```json highlight={2,6-8} theme={null}
{
  "status": "processed",
  "results": {
    "parse": {"…": "…"},
    "extractions": [{"fields": {
      "invoice_number": {"value": "INV-2024-0847", "confidence": 97.0},
      "total_amount":   {"value": "4087.50",       "confidence": 96.0},
      "issue_date":     {"value": "2024-03-15",    "confidence": 93.0}
    }}]
  }
}
```

* `results` holds one section per node type that ran. This workflow has a parse node and an extract node, so `parse` and `extractions` are filled.
* `extractions` is a list. One entry per extraction the run produced.
* `fields` is keyed by the field names you defined in step 1.
* `value` is a string on the wire, including for `float` and `date` fields. `confidence` is a number from 0 to 100.
* `parse` is trimmed above. It holds the parsed markdown, the plain text, per-page blocks, and their bounding boxes.

Each field also carries `evidence`: the snippet and page number the value came from. [Runs & results](/concepts/runs-and-results) is the full envelope, section by section, and [Get run](/api-reference-v3/runs/get) lists every field.

<Accordion title="The whole thing as one script">
  ```typescript TypeScript theme={null}
  import { Anyformat, Schema } from "@anyformat/sdk";

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

  const result = await af
    .workflow("Invoice Processing", "Extract key data from invoices")
    .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"),
    ])
    .run(file)
    .wait();

  console.log(result.field("invoice_number")?.value);
  console.log(result.field("total_amount")?.value);
  console.log(result.field("issue_date")?.value);
  ```

  ```python Python theme={null}
  import os
  from anyformat.sdk import Client
  from anyformat.workflow import Schema

  client = Client(api_key=os.environ["ANYFORMAT_API_KEY"])

  workflow = (
      client.workflow("Invoice Processing")
      .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()
  )

  result = workflow.run("invoice.pdf").wait()

  print(result.fields["invoice_number"].value)
  print(result.fields["total_amount"].value)
  print(result.fields["issue_date"].value)
  ```
</Accordion>

## Where to go next

<CardGroup cols={2}>
  <Card title="API reference" icon="code" href="/api-reference-v3/introduction">
    Every endpoint, every response, every error code
  </Card>

  <Card title="Runs & results" icon="list-check" href="/concepts/runs-and-results">
    The full results envelope, confidence, and evidence
  </Card>

  <Card title="Recipes" icon="book-open" href="/examples/index">
    End-to-end examples: invoices, resumes, contracts, receipts, and more
  </Card>

  <Card title="Coding assistant" icon="robot" href="/guides/coding-assistant">
    Let Claude Code build and run anyformat workflows from your editor
  </Card>
</CardGroup>
