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

# Report generator

> Fills a Markdown template with the fields an Extract node read and returns the finished report as a file.

**Report generator** turns extracted data into a written report. You give it a Markdown template. After [Extract](https://docs.anyformat.ai/guides/nodes/extract.md) finishes, the node fills the template with the extracted values and stores the result as a Markdown file you can download.

Saving the workflow stores the template only. No model runs until a document does.

## The node

```json API theme={null}
{
  "id": "report_1",
  "type": "report_generator",
  "instructions": "Write amounts with two decimals.",
  "example_report": "# Invoice summary\n\nVendor: {{vendor}}\nTotal: {{total}}"
}
```

```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 report")
    .parse()
    .extract([Schema.string("vendor", "Vendor name"), Schema.float("total", "Invoice total")])
    .report_generator(
        "Write amounts with two decimals.",
        "# Invoice summary\n\nVendor: {{vendor}}\nTotal: {{total}}",
    )
    .create()
)
```

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

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

const workflow = await af
  .workflow("Invoice report")
  .parse()
  .extract([Schema.string("vendor", "Vendor name"), Schema.float("total", "Invoice total")])
  .reportGenerator(
    "Write amounts with two decimals.",
    "# Invoice summary\n\nVendor: {{vendor}}\nTotal: {{total}}",
  )
  .create();
```

## Options

| Field | Type | Default | What it does |
| - | - | - | - |
| `example_report` | string | `null` | The Markdown template to fill, up to 64 KiB. Studio and both builders require it to be non-blank. |
| `instructions` | string | `""` | Extra guidance for filling the template, for example how to format numbers or dates. |

The schema the API accepts is generated from the same source: [Report generator node schema](https://docs.anyformat.ai/api-reference-v3/node-schemas.md#report_generator).

## Connects to

[Extract](https://docs.anyformat.ai/guides/nodes/extract.md)

[Report generator](https://docs.anyformat.ai/guides/nodes/report-generator.md)

Only a single Extract feeds Report generator, and nothing follows it.

Report generator reads the Extract node that feeds it, through exactly one incoming edge. The Python and TypeScript builders add it only to a workflow with a single Extract; send the node in the API JSON to attach it to one branch of a classified workflow.

## What it returns

The node fills the `reports` section of the [run results](https://docs.anyformat.ai/concepts/runs-and-results.md): one entry per split the node generated a report for.

```json theme={null}
{
  "reports": [
    {
      "node_id": "report_1",
      "split_id": null,
      "status": "succeeded",
      "download_url": "https://storage.anyformat.ai/reports/invoice.md?X-Amz-Signature=…"
    }
  ]
}
```

`status` is `pending`, `succeeded` or `failed`. `download_url` is valid for 15 minutes from the moment the response was built, so re-read the run for a fresh link. In the Python SDK, `run.wait().reports` holds the same entries.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.