Reports
Generate and retrieve AI analysis reports across all interviews in a project.
Once a project has completed interviews, Persona can generate a structured analysis report — surfacing themes, representative quotes, and a high-level synthesis across all responses.
Generate a report
Triggers report generation for a project, analysing all completed interviews. This is asynchronous and typically takes 1-3 minutes depending on interview volume. If a report already exists it is regenerated and replaces the previous one. Poll `GET /projects/{project_id}/report` until `status` is `COMPLETED`.
Authentication
x-api-key headerPath Parameters
| Name | Type | Description |
|---|---|---|
project_id* | string | — |
Headers
| Name | Type | Description |
|---|---|---|
x-api-key | string | — |
Responses
| Field | Type | Description |
|---|---|---|
report_idrequired | string | Report Id |
project_idrequired | string | Project Id |
statusrequired | string | — |
Triggers report generation. This is asynchronous — the report typically takes 1–3 minutes depending on interview volume. If a report already exists it is regenerated and replaces the previous one.
POST /v1/projects/{project_id}/report
curl -X POST "https://external-api.prod.insightscompany.io/v1/projects/<project_id>/report" \
-H "x-api-key: <api_key>"Example response
Response 200
{
"project_id": "846acb65-4c97-491d-8a4a-7135c9ea72d9",
"report_id": "b2c3d4e5-0000-0000-0000-000000000001",
"status": "PROCESSING"
}Poll Get Report until status is COMPLETED.
Get a report
Returns the latest generated report for a project.
Authentication
x-api-key headerPath Parameters
| Name | Type | Description |
|---|---|---|
project_id* | string | — |
Headers
| Name | Type | Description |
|---|---|---|
x-api-key | string | — |
Responses
| Field | Type | Description |
|---|---|---|
report_idrequired | string | Report Id |
project_idrequired | string | Project Id |
statusrequired | PROCESSINGCOMPLETEDFAILED | — |
generated_at | string | Generated At |
interviews_analysed | integer | Interviews Analysed |
summary | string | — |
themes | object[] | — |
Returns the latest generated report for a project, or the status of an in-flight generation.
GET /v1/projects/{project_id}/report
curl "https://external-api.prod.insightscompany.io/v1/projects/<project_id>/report" \
-H "x-api-key: <api_key>"Example response
Response 200
{
"generated_at": "2025-06-20T15:00:00Z",
"interviews_analysed": 38,
"project_id": "846acb65-4c97-491d-8a4a-7135c9ea72d9",
"report_id": "c3d4e5f6-0000-0000-0000-000000000001",
"status": "COMPLETED",
"summary": "The majority of churned customers cited pricing as the primary driver, followed by missing integrations with their existing toolchain.",
"themes": [
{
"frequency": 0.68,
"quotes": [
"It wasn't that we didn't love the product — our budget just got cut.",
"We compared it to alternatives and the pricing didn't stack up for our team size."
],
"summary": "Over two thirds of participants mentioned price as a factor, often in the context of budget cuts rather than perceived value.",
"title": "Pricing concerns"
},
{
"frequency": 0.41,
"quotes": [
"We needed it to work with our CRM out of the box."
],
"summary": "Participants wanted native integrations with tools they were already using.",
"title": "Missing integrations"
}
]
}Response reference
| Field | Type | Description |
|---|---|---|
status | enum | PROCESSING, COMPLETED, or FAILED |
interviews_analysed | integer | Interviews included in this report |
summary | string | High-level synthesis across all interviews |
themes | array | Key themes, sorted by frequency descending |
themes[].frequency | float | Proportion of interviews that surfaced this theme (0–1) |
themes[].summary | string | AI interpretation of this theme |
themes[].quotes | array | Verbatim participant quotes supporting this theme |
Polling pattern
import time, requests
def wait_for_report(project_id, api_key, base_url):
url = f"{base_url}/v1/projects/{project_id}/report"
headers = {"x-api-key": api_key}
for _ in range(20): # max ~3 minutes
r = requests.get(url, headers=headers).json()
if r["status"] == "COMPLETED":
return r
if r["status"] == "FAILED":
raise Exception("Report generation failed")
time.sleep(10)
raise TimeoutError("Report did not complete in time")Notes
- A report requires at least one completed interview.
- Generating a new report replaces the previous one for that project.
- For raw per-interview data, use Interview Records instead.