> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.alfa.boosted.ai/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.alfa.boosted.ai/_mcp/server.

# Create and manage reports

Reports are the execution results of your workplans. Each time you run a workplan, it generates a new report with fresh analysis based on current data. This guide explains how to create, monitor, and retrieve reports from your workplans.

## Running a workplan to generate a report

Once your workplan is ready, `status == "READY"`, you can execute it to generate a new report.

```python
import requests

BASE_URL = "https://alfa.boosted.ai/client"
API_KEY = "YOUR_API_KEY_HERE"

headers = {"x-api-key": API_KEY, "Content-Type": "application/json"}

def run_workplan(workplan_id):
    """Execute a workplan to generate a new report."""
    url = f"{BASE_URL}/v2/workplans/{workplan_id}/run-workplan"
    
    response = requests.post(url, headers=headers)
    
    if response.status_code == 200:
        data = response.json()
        report_id = data.get("report_id")
        status = data.get("status")
        print(f"Workplan execution started! Report ID: {report_id}")
        print(f"Current status: {status}")
        return report_id
    else:
        print(f"Error: {response.status_code}, {response.text}")
        return None

# Run a workplan to generate a new report
workplan_id = "your-workplan-id"
report_id = run_workplan(workplan_id)
```

## Monitoring report generation

After starting a workplan execution, you can monitor the report's progress.

```python
import time

def get_report_status(report_id):
    """Check the status of a report generation."""
    url = f"{BASE_URL}/v2/reports/{report_id}/results"
    
    response = requests.get(url, headers=headers)
    
    if response.status_code == 200:
        data = response.json()
        status = data.get("status")
        created_at = data.get("created_at")
        print(f"Report {report_id}: {status} (created: {created_at})")
        return status
    else:
        print(f"Error: {response.status_code}, {response.text}")
        return None

# Poll until the report is complete
report_status = ""
while report_status not in ["COMPLETE", "ERROR", "CANCELLED"]:
    report_status = get_report_status(report_id)
    
    if report_status in ["ERROR", "CANCELLED", "NO_RESULTS_FOUND"]:
        print(f"Report execution encountered an issue: {status}")
        break
    if report_status != "COMPLETE":
        print("Report still processing... status: {report_status}")
        time.sleep(10)
```

## Report status values

Reports can be in the following states during generation:

* `NOT_STARTED`: The report generation hasn't begun yet
* `STARTING`: The workplan execution is being initialized
* `RUNNING`: The workplan is actively processing and generating results
* `COMPLETE`: The report has been successfully generated
* `ERROR`: An error occurred during report generation
* `CANCELLED`: The report generation was stopped before completion
* `NO_RESULTS_FOUND`: The workplan completed but couldn't find relevant results
* `TOKEN_LIMIT`: The workplan hit the token usage limit

## Retrieving report output

Once a report is complete, you can retrieve the analysis results.

```python
def get_report_results(report_id):
    """Get the complete results of a generated report."""
    url = f"{BASE_URL}/v2/reports/{report_id}/results"
    
    response = requests.get(url, headers=headers)
    
    if response.status_code == 200:
        return response.json()
    else:
        print(f"Error: {response.status_code}, {response.text}")
        return None

# Get the complete report results
report_results = get_report_results(report_id)
```

Report outputs can be of different types:

* `text`: Plain text analysis and explanations
* `table`: Structured data in tabular format
* `graph`: Visual representation of data as a line, bar, or pie chart

### Example: Processing different output types

Reports can contain multiple types of outputs. Here's how to handle each type:

```python
# Get the complete report results
report_results = get_report_results(report_id)

if report_results and "outputs" in report_results:
    for i, item in enumerate(report_results["outputs"]):
        output_data = item["output"]
        output_type = output_data["output_type"]
        
        print(f"\n--- Output {i+1} ({output_type}) ---")
        
        if output_type == "text":
            # Save the text analysis to a file
            with open(f"analysis_{i+1}.txt", "w") as f:
                f.write(output_data["val"])
            print(f"Text analysis saved to analysis_{i+1}.txt")
            
        elif output_type == "table":
            # Export the table to CSV
            import csv
            
            columns = [col["name"] for col in output_data["columns"]]
            with open(f"table_{i+1}.csv", "w", newline="") as f:
                writer = csv.writer(f)
                writer.writerow(columns)
                writer.writerows(output_data["rows"])
            print(f"Table data exported to table_{i+1}.csv")
            
        elif output_type == "graph":
            # Just print info about the graph (in a real app, you might render it)
            graph_type = output_data["graph"]["graph_type"]
            title = output_data["title"]
            print(f"Graph: {title} ({graph_type})")
```

## Cancelling report generation

If you need to stop a report that's currently being generated, there is an endpoint for that. Note that

```python
def cancel_report(report_id):
    """Cancel a report that is currently being generated."""
    url = f"{BASE_URL}/v2/reports/{report_id}/cancel"
    
    response = requests.post(url, headers=headers)
    
    if response.status_code == 200:
        data = response.json()
        success = data.get("success", False)
        if success:
            print(f"Report {report_id} cancelled successfully")
        return success
    else:
        print(f"Error: {response.status_code}, {response.text}")
        return False

# Cancel a report if needed
cancel_report(report_id)
```

## Listing all your reports

Get an overview of all reports across all your workplans:

```python
def list_all_reports():
    """List all reports across all workplans."""
    url = f"{BASE_URL}/v2/reports"
    
    response = requests.get(url, headers=headers)
    
    if response.status_code == 200:
        data = response.json()
        reports = data.get("reports", [])
        
        print(f"Total reports: {len(reports)}")
        
        for report in reports:
            print(f"\nReport {report["report_id"]}:")
            print(f"  Workplan: {report["workplan_id"]}")
            print(f"  Status: {report["status"]}")
            print(f"  Created: {report["created_at"]}")
        
        return reports
    else:
        print(f"Error: {response.status_code}, {response.text}")
        return None

# List all reports
all_reports = list_all_reports()
```

## Example: Complete workplan execution

Here's a complete example of creating and running a workplan to generate a report:

#### Create a workplan

First, create a workplan for your analysis:

```python
# Create a workplan for market analysis
workplan_prompt = "Analyze Apple's stock performance over the last month and show key metrics in a table"
workplan_id = create_workplan(workplan_prompt)
print(f"Created workplan: {workplan_id}")
```

#### Wait for workplan to be ready

Monitor the workplan status until it's ready:

```python
# Wait for workplan to be ready
while True:
    plan_status, run_status = get_workplan_status(workplan_id)
    if plan_status == "READY":
        print("Workplan is ready to execute!")
        break
    elif plan_status == "FAILED":
        print("Workplan creation failed")
        exit(1)
    time.sleep(10)
```

#### Execute the workplan

Run the workplan to generate a report:

```python
# Execute the workplan
report_id = run_workplan(workplan_id)
print(f"Started report generation: {report_id}")
```

#### Monitor report progress

Wait for the report to complete:

```python
# Monitor report generation
while True:
    status = get_report_status(report_id)
    if status == "COMPLETE":
        print("Report generation completed!")
        break
    elif status in ["ERROR", "CANCELLED"]:
        print(f"Report failed with status: {status}")
        exit(1)
    time.sleep(10)
```

#### Retrieve results

Get the final report results:

```python
# Get the report results
results = get_report_results(report_id)
process_report_outputs(results)
```

## Next steps

Now that you understand how to create and manage reports, you can:

* Learn how to [schedule and automate workplans](/guides/build-with-alfa/scheduling-workplans/schedule-and-automate-workplans) to run on a custom schedule
* Learn how to [monitor token usage](/guides/build-with-alfa/workplans/track-token-usage) efficiently build reports
* Explore using [documents](/guides/build-with-alfa/knowledge-base/documents) with your workplans

> **Tip**
>
> Each report execution consumes tokens and generates fresh analysis based on current data. Consider your token budget when running workplans frequently.