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

# Quickstart

> Build your first workflow and extract data from a document end-to-end — in the UI, with curl, with the TypeScript SDK, or with the Python SDK.

The walkthrough below has tabs at each step — pick **UI** to drive everything from [app.anyformat.ai](https://app.anyformat.ai), or **curl** / **TypeScript** / **Python** to drive the [API](/api-reference/introduction) directly. The four paths produce the same result.

<Tip>
  **Not a developer?** Follow the **UI** tab the whole way down and ignore curl / TypeScript / Python — you can build and run everything from [app.anyformat.ai](https://app.anyformat.ai) without writing any code. For more advanced workflows (sorting documents by type, splitting files, validation rules), see **[Studio](/guides/studio/index)**.

  Even if you *do* plan to integrate via the API, we recommend building your **first** workflow in the UI — it's faster to iterate on fields visually, and once it works you can copy the workflow ID and call it from code.
</Tip>

***

## Before you start

<Tabs>
  <Tab title="UI" icon="browser">
    Create an account at [app.anyformat.ai](https://app.anyformat.ai). That's it.
  </Tab>

  <Tab title="curl" icon="terminal">
    Get an API key from [app.anyformat.ai/api-key](https://app.anyformat.ai/api-key). Export it for the snippets below:

    ```bash theme={null}
    export ANYFORMAT_API_KEY="your_api_key_here"
    ```
  </Tab>

  <Tab title="TypeScript" icon="js" iconType="brands">
    Install the SDK (Node 18+):

    ```bash theme={null}
    npm install @anyformat/sdk
    ```

    Get an API key from [app.anyformat.ai/api-key](https://app.anyformat.ai/api-key) and pass it to the constructor — or set `ANYFORMAT_API_KEY` and read it from the environment:

    ```bash theme={null}
    export ANYFORMAT_API_KEY="your_api_key_here"
    ```
  </Tab>

  <Tab title="Python" icon="python" iconType="brands">
    Install the SDK (Python 3.13 — see the [SDK page](/api-reference/sdks/python) for the pin):

    ```bash theme={null}
    pip install anyformat
    ```

    Get an API key from [app.anyformat.ai/api-key](https://app.anyformat.ai/api-key) and pass it to the `Client` — or set `ANYFORMAT_API_KEY` and pick it up from the environment:

    ```bash theme={null}
    export ANYFORMAT_API_KEY="your_api_key_here"
    ```
  </Tab>
</Tabs>

***

## 1. Create a workflow

A workflow defines what data to extract. We'll build a simple invoice processor with three fields: `invoice_number`, `total_amount`, `issue_date`.

<Tabs>
  <Tab title="UI" icon="browser">
    1. From the home screen, type a description of what you want to extract (e.g. *"Invoice processing: extract invoice number, total, and issue date"*).
    2. Drag in a sample invoice PDF (optional but recommended — anyformat will suggest fields from the document).
    3. Click the **send icon** (the arrow button in the text box) to start.

    anyformat opens the workflow workspace with the document on the left and the fields panel on the right. Review the suggested fields and adjust as needed.

    <video autoPlay loop muted playsInline className="w-full rounded-lg" aria-label="Creating a workflow from the home screen">
      <source src="https://mintcdn.com/anyformat/Lj-IYCar0l6vJwHb/images/createfromhome.mp4?fit=max&auto=format&n=Lj-IYCar0l6vJwHb&q=85&s=46b2373841ed99b84e6763d1f6f0d7be" type="video/mp4" data-path="images/createfromhome.mp4" />
    </video>

    Once your fields look right, copy the workflow ID from the URL or workflow settings — you'll need it if you want to run this workflow via the API later.
  </Tab>

  <Tab title="curl" icon="terminal">
    A workflow is a [typed graph](/concepts/workflows) of nodes. The minimal extraction shape is a `parse` node feeding an `extract` node — two nodes, one edge.

    ```bash theme={null}
    curl -X POST 'https://api.anyformat.ai/v2/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", "description": "The unique invoice identifier",       "data_type": "string"},
                {"name": "total_amount",   "description": "Total invoice amount",                "data_type": "float"},
                {"name": "issue_date",     "description": "Date when the invoice was issued",    "data_type": "date"}
              ]
            }
          }
        ],
        "edges": [{"source": "parse_1", "target": "extract_1"}]
      }'
    ```

    The response contains your workflow ID:

    ```json theme={null}
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "name": "Invoice Processing",
      "description": "Extract key data from invoices",
      "created_at": "2024-01-01T00:00:00.000Z",
      "updated_at": "2024-01-01T00:00:00.000Z"
    }
    ```
  </Tab>

  <Tab title="TypeScript" icon="js" iconType="brands">
    The SDK exposes a fluent builder over the same [typed graph](/concepts/workflows).

    ```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}`);
    ```
  </Tab>

  <Tab title="Python" icon="python" iconType="brands">
    The SDK exposes a fluent builder over the same [typed graph](/concepts/workflows).

    ```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}")
    ```
  </Tab>
</Tabs>

<Tip>
  This is the simple Parse → Extract shape. You can also build parse-only workflows, sort mixed document types with Classify, or split multi-document files — all by arranging the steps yourself in **[Studio](/guides/studio/index)**.
</Tip>

***

## 2. Run the workflow on a document

<Tabs>
  <Tab title="UI" icon="browser">
    From the workflow workspace, drag in (or upload via the **Add document** button) the invoice you want to process. Processing starts automatically and usually completes in 10–60 seconds depending on the document.

    You can also open a single document (click its filename) and run it from the **Process document** button on the right.

    <video autoPlay loop muted playsInline className="w-full rounded-lg" aria-label="Running documents">
      <source src="https://mintcdn.com/anyformat/Lj-IYCar0l6vJwHb/images/rundocuments.mp4?fit=max&auto=format&n=Lj-IYCar0l6vJwHb&q=85&s=8362804a41cff062864c121e9d6c8646" type="video/mp4" data-path="images/rundocuments.mp4" />
    </video>
  </Tab>

  <Tab title="curl" icon="terminal">
    Replace `WORKFLOW_ID` with the ID returned in step 1.

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

    The response returns a file ID — keep it; you'll use it to poll for results:

    ```json theme={null}
    {
      "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
      "status": "pending",
      "workflow_id": "550e8400-e29b-41d4-a716-446655440000",
      "version_id": "FGaV4I2JAA"
    }
    ```

    `status: "pending"` means the run was accepted, not that extraction has finished — poll the results endpoint. `version_id` records the workflow version your run was bound to, which lets you verify which schema produced the results (useful right after an edit).
  </Tab>

  <Tab title="TypeScript" icon="js" iconType="brands">
    The TS SDK collapses "submit + poll" into a single `.run(file).wait()` chain. Build the same workflow shape (or look it up by id with the low-level client) and call `.run(file)` on it:

    ```typescript theme={null}
    const file: File = /* a File with .name set, e.g. 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
    ```
  </Tab>

  <Tab title="Python" icon="python" iconType="brands">
    ```python theme={null}
    run = workflow.run("invoice.pdf")  # Path | str | bytes
    ```
  </Tab>
</Tabs>

***

## 3. Get the extracted data

<Tabs>
  <Tab title="UI" icon="browser">
    Results appear in the workflow workspace as soon as processing finishes — no refresh needed.

    * **Table view** shows all your documents at once. The first tab lists your documents (one row each); extra tabs show the output of each step in your workflow.
    * **Document view** (click a filename) shows one document on its own, with each extracted value highlighted on the page it came from — click a field to see where it came from.

    Export the results as **CSV**, **Excel**, or **JSON** from the workflow view. See [Outputs](/concepts/outputs) for the differences.
  </Tab>

  <Tab title="curl" icon="terminal">
    Poll the results endpoint. It returns **412** while processing and **200** when the run is done.

    ```bash theme={null}
    curl -H "Authorization: Bearer $ANYFORMAT_API_KEY" \
      "https://api.anyformat.ai/v2/workflows/WORKFLOW_ID/files/FILE_ID/results/"
    ```

    For production integrations, use [webhooks](/api-reference/webhooks/overview) instead of polling — webhooks deliver results immediately and don't consume rate limit.
  </Tab>

  <Tab title="TypeScript" icon="js" iconType="brands">
    `wait()` polls until the run completes (412 → still going, 200 → done) and returns a typed `Result`.

    ```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);
    ```
  </Tab>

  <Tab title="Python" icon="python" iconType="brands">
    `wait()` polls until the run completes (412 → still going, 200 → done) and returns a typed `Result`.

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

    For production integrations, use [webhooks](/api-reference/webhooks/overview) instead of polling.
  </Tab>
</Tabs>

A completed result looks like this (one section per node type that ran — `parse` and `extractions` here; `classifications` and `splits` are empty because this workflow has neither):

```json theme={null}
{
  "collection_id": "069dcc2c-e14c-7606-8000-2ee4fb17b4e1",
  "verification_url": "https://app.anyformat.ai/workflows/.../files/...",
  "parse": { "markdown": "<DOCUMENT id=\"1\" page=\"1\">...", "text": "...", "parse_confidence": 94.2, "layout_confidence": 87.4, "blocks": [] },
  "classifications": [],
  "splits": [],
  "extractions": [
    {
      "split_name": null,
      "partition": null,
      "fields": {
        "invoice_number": {
          "value": "INV-2024-0847",
          "confidence": 97.0,
          "evidence": [{"text": "Invoice #INV-2024-0847", "page_number": 1}],
          "verification_status": "not_verified"
        },
        "total_amount": {
          "value": 4087.50,
          "confidence": 96.0,
          "evidence": [{"text": "Total: $4,087.50", "page_number": 2}],
          "verification_status": "not_verified"
        },
        "issue_date": {
          "value": "2024-03-15",
          "confidence": 93.0,
          "evidence": [{"text": "Date: March 15, 2024", "page_number": 1}],
          "verification_status": "not_verified"
        }
      }
    }
  ]
}
```

See [Runs & results](/concepts/runs-and-results) for the model behind these sections, and [Response formats](/api-reference/response-formats) for every field in the envelope.

***

## Complete script

The three steps above are narrative slices of the same script. Here they are end-to-end as a single pasteable block.

<Tabs>
  <Tab title="TypeScript" icon="js" iconType="brands">
    ```typescript theme={null}
    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 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);
    ```
  </Tab>

  <Tab title="Python" icon="python" iconType="brands">
    ```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)
    ```
  </Tab>
</Tabs>

***

## Where to go next

<CardGroup cols={2}>
  <Card title="Build workflows" icon="plus" href="/guides/workflows/creating">
    Deeper walkthrough of the Define → Refine → Publish lifecycle in the UI
  </Card>

  <Card title="Recipes" icon="book-open" href="/guides/recipes/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>

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