# POST /api/v1/reports

> Generate report

- **Tag:** reports
- **Operation ID:** `generate_report_api_v1_reports_post`

## Description

Queue a report for generation and return task ID for tracking.

## Authentication

Bearer token in `Authorization` header.
Required header: `x-business-id: <business uuid>`.

## Request body

Schema: `ReportCreateRequest`

- `report_name` (string · required) — Report type identifier. Must match a supported report_name from the /reports endpoint. Examples: 'master_transactions', 'trial_balance', 'general_ledger', 'profit_and_loss_comparative', 'ar_report', 'cogs_report', 'shareholder_loans'. See GET /reports for the complete list of available report types.
- `period_type` (ReportPeriodType) — Controls how report dates are determined. 'custom' (default): Use start_date/end_date fields directly. 'tax_year': Calculate full fiscal year dates from business's tax_year_end_month config. 'tax_quarter': Calculate quarter dates within a fiscal year. When using tax_year or tax_quarter, the resolved dates will be stored in generation_params.
- `tax_year` (integer) — The tax/fiscal year for period calculation. Required when period_type is 'tax_year' or 'tax_quarter'. Example: 2026. The actual date range depends on the business's tax_year_end_month setting. For a business with tax year ending March 31, tax_year=2026 covers April 1, 2025 through March 31, 2026.
- `tax_quarter` (integer) — The quarter within the tax year (1-4). Required when period_type is 'tax_quarter'. Q1 is the FIRST quarter of the fiscal year, which may start in the prior calendar year for non-calendar fiscal years. Example: For a March fiscal year-end, Q1 of tax_year=2026 covers April 1-June 30, 2025.
- `start_date` (string) — Report period start date in YYYY-MM-DD format (e.g., '2026-01-01'). Required when period_type='custom' for reports with input_type='date_start_end' or similar. Ignored when period_type is 'tax_year' or 'tax_quarter' (dates calculated automatically).
- `end_date` (string) — Report period end date in YYYY-MM-DD format (e.g., '2026-12-31'). Required when period_type='custom' for date-range reports. For point-in-time reports (input_type='date_end_only'), only end_date is needed. Ignored when period_type is 'tax_year' or 'tax_quarter'.
- `comparison_period_type` (ReportPeriodType) — Period type for the comparison/prior period in comparative reports. Same options as period_type: 'custom', 'tax_year', or 'tax_quarter'. Used with reports like 'profit_and_loss_comparative' and 'balance_sheet_comparative' to enable variance analysis between two periods.
- `comparison_tax_year` (integer) — Tax year for the comparison period. Used when comparison_period_type is 'tax_year' or 'tax_quarter'. Example: Set to 2025 to compare against the current period's 2026 for year-over-year analysis.
- `comparison_tax_quarter` (integer) — Quarter (1-4) for the comparison period. Required when comparison_period_type is 'tax_quarter'. Example: comparison_tax_quarter=1 with comparison_tax_year=2025 compares Q1 2025 against the current period.
- `comparison_start_date` (string) — Start date for comparison period in YYYY-MM-DD format. Used when comparison_period_type='custom' for comparative reports. Example: '2025-01-01' to compare against prior year.
- `comparison_end_date` (string) — End date for comparison period in YYYY-MM-DD format. Used when comparison_period_type='custom' for comparative reports. Example: '2025-12-31' to compare full prior year.
- `ledger_id` (string) — UUID of a specific ledger account to filter the report. Currently used with 'general_ledger' report to show transactions for only one account instead of all accounts. When omitted, the general_ledger report includes all accounts. Example: '019ab37c-ledg-7000-8000-000000000001'.
- `instance_id` (string) — Teal integration instance ID. Optional - if not specified, uses the business's default Teal instance. Only needed for businesses with multiple Teal instances or when overriding the default. Used for reports that fetch data from Teal (P&L, Balance Sheet).
- `file_s3_key` (string) — S3 object key for file-based report inputs. Required for reports with input_type='file_upload' (e.g., 'cogs_report'). The file should be uploaded first via the upload endpoint. Example: 'uploads/business-123/cogs-data-2026.csv'.
- `s3_keys` (array · string) — Array of S3 object keys when a report requires multiple input files. Each key should reference a previously uploaded file. Example: ['uploads/business-123/sales-q1.csv', 'uploads/business-123/sales-q2.csv'].
- `tag_group_id` (string) — UUID of a specific tag group to filter the report. Used with 'pnl_by_department' to segment by tags within this group.
- `tag_ids` (array · string) — List of specific tag UUIDs to filter the report. When multiple tags are provided for 'pnl_by_department', it generates a multi-sheet report with one P&L statement per tag.
- `additional_params` (object) — Report-specific parameters that vary by report type. Supported parameters: **customer_id** (UUID): Filter customer_statements or pnl_by_customer to a specific customer. **vendor_id** (UUID): Filter vendor_statements to a specific vendor. **include_zero_balances** (bool): Include zero-balance accounts in trial_balance report. **tag_group_id** (UUID): Filter pnl_by_department to tags in a specific tag group. **forecast_days** (int): Number of days to forecast in cash_flow_forecast (default: 90). **raw** (bool): For general_ledger only — return a single flat sheet with no formatting or headers (default: false). Example: {'customer_id': '019abc-uuid', 'include_zero_balances': true}.
- `output_format` (ReportOutputFormat) → `ReportOutputFormat` — Output file format for the report. 'xlsx' (default): Excel format with formatting, multiple tabs, headers, and currency formatting. 'csv': Comma-separated values format as a single flat file without formatting. CSV is useful for importing into other systems or programmatic analysis.

## Responses

### 202 — Successful Response

Schema: `ReportTaskResponse`

- `task_id` (string · required) — Unique identifier for the report generation task. Use this to poll for status via GET /reports/task/{task_id}. Also serves as the Temporal workflow ID. Format: 'report-generation-{business_id}-{report_name}-{date_params}'. Example: 'report-generation-bus123-profit_and_loss-start-2026-01-01-end-2026-12-31'.
- `status` (string · required) — Initial status of the task. Typically 'queued' for new requests or 'in_progress' if a duplicate request was made while an identical report is already being generated. Values: 'queued', 'in_progress', 'failed'.
- `message` (string) — Human-readable message about the task status. Provides context such as 'Report generation queued successfully with Temporal' or error details if the request failed validation.
- `business_id` (string · required) — UUID of the business for which the report is being generated. Echoed from the request for confirmation.
- `report_name` (string · required) — Type of report being generated. Echoed from the request for confirmation. Example: 'profit_and_loss', 'master_transactions', 'cogs_report'.

### 400 — Bad Request - Invalid input

### 401 — Unauthorized - Authentication required

### 403 — Forbidden - Insufficient permissions

### 422 — Validation Error

Schema: `HTTPValidationError`

- `detail` (array · ValidationError) → `ValidationError`
  - `loc` (array · string | integer · required)
  - `msg` (string · required)
  - `type` (string · required)
  - `input` (object)
  - `ctx` (object)

## Code samples

### cURL

```bash
curl -X POST 'https://api.ondayzero.com/api/v1/reports' \
  -H 'Authorization: Bearer dz_your_token' \
  -H 'x-business-id: YOUR_BUSINESS_ID' \
  -H 'Content-Type: application/json' \
  -d '{
  "report_name": "string"
}'
```

### JavaScript

```javascript
const response = await fetch('https://api.ondayzero.com/api/v1/reports', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer dz_your_token',
    'x-business-id': 'YOUR_BUSINESS_ID',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
  "report_name": "string"
}),
});
const data = await response.json();
```

### Python

```python
import httpx

headers = {
    "Authorization": "Bearer dz_your_token",
    "x-business-id": "YOUR_BUSINESS_ID",
}

payload = {
  "report_name": "string"
}

response = httpx.post("https://api.ondayzero.com/api/v1/reports", headers=headers, json=payload)
data = response.json()
```

## See also

- HTML version: https://www.ondayzero.com/docs/reference/reports/generate-report
- OpenAPI slice: https://www.ondayzero.com/docs/reference/reports/generate-report/openapi.json
- Other endpoints in **reports**: https://www.ondayzero.com/docs/reference/reports
