Query (RAG)
The Query API answers natural-language questions about your transcripts using retrieval-augmented generation (RAG). Each question is embedded, the most similar transcript segments are retrieved from the vector store, and the answer is generated from only those excerpts. Every response includes the source segments the answer is grounded in, with speaker and timestamp information.
All endpoints require authentication and are scoped to the authenticated workspace. See Authentication.
Base URL: https://api.perceive8.com
Endpoints
| Method | Path | Purpose |
|---|---|---|
POST |
/v1/query |
Ask a question about your transcripts |
GET |
/v1/query/history/{analysis_id} |
Fetch the transcript segments of an analysis |
POST |
/v1/query/backfill |
Embed existing transcripts into the vector store |
POST /v1/query
Ask a question about your transcripts. If analysis_id is omitted, the search runs across all of your analyses; otherwise it is restricted to that analysis. The answer is generated only from the retrieved transcript excerpts — if the answer is not in the excerpts, the model says so — and cites speakers and timestamps.
Request body
| Field | Type | Required | Description |
|---|---|---|---|
question |
string | Yes | The natural-language question to answer. |
analysis_id |
string | No | Restrict the search to a single analysis. The analysis must belong to your workspace, otherwise the request fails with 404. |
playbook_id |
string | No | Steer the answer with a playbook. The answer prioritizes findings relevant to the playbook's name, description, and configured questions. |
{
"question": "What concerns did the customer raise about pricing?",
"analysis_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7"
}
Response 200 OK
| Field | Type | Description |
|---|---|---|
answer |
string | The generated answer. When no relevant segments are found, this is No relevant transcript segments found for this analysis. |
sources |
array of objects | The transcript segments the answer is grounded in. Empty when nothing matched. |
Each entry in sources:
| Field | Type | Description |
|---|---|---|
analysis_id |
string | The analysis the segment belongs to. |
speaker_name |
string | null | Speaker label for the segment. |
start_time |
number | Segment start time, in seconds from the start of the audio. |
end_time |
number | Segment end time, in seconds. |
text |
string | The segment text. |
relevance_score |
number | Vector similarity between the segment and the question. |
{
"answer": "The customer raised two pricing concerns. [Customer, 04:12-04:38]: they asked whether the per-seat price applies to view-only members. [Customer, 11:03-11:20]: they requested a discount for annual prepayment.",
"sources": [
{
"analysis_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"speaker_name": "Customer",
"start_time": 252.4,
"end_time": 278.1,
"text": "Does the per-seat price also apply to view-only members?",
"relevance_score": 0.87
},
{
"analysis_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"speaker_name": "Customer",
"start_time": 663.0,
"end_time": 680.5,
"text": "If we prepay annually, is there a discount?",
"relevance_score": 0.82
}
]
}
curl -X POST https://api.perceive8.com/v1/query \
-H "X-API-Key: pk_live_xxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{"question": "What concerns did the customer raise about pricing?"}'
Errors
| Status | When |
|---|---|
404 |
analysis_id was provided but no analysis with that id exists in your workspace. |
502 |
The query failed while embedding, searching, or generating the answer. |
503 |
The query service is not available. |
GET /v1/query/history/{analysis_id}
Return the transcript segments of an analysis, ordered by start_time. Despite the name, this returns transcript segments — not previously asked questions. It supports delta loading for live-stream polling: pass the id of the last segment you received as after_id to get only newer segments.
Parameters
| Name | In | Type | Required | Description |
|---|---|---|---|---|
analysis_id |
path | string | Yes | The analysis to fetch segments for. Must belong to your workspace. |
after_id |
query | string | No | Return only segments whose start_time is greater than the start time of the segment with this id. An invalid id is ignored and all segments are returned. |
limit |
query | integer | No | Maximum number of segments to return. Default 1000. |
Response 200 OK
| Field | Type | Description |
|---|---|---|
analysis_id |
string | The requested analysis id. |
segments |
array of objects | Transcript segments, ordered by start_time. |
total |
integer | Number of segments returned in this response. |
Each entry in segments:
| Field | Type | Description |
|---|---|---|
id |
string | Segment id. Pass it as after_id for delta loading. |
text |
string | The segment text. |
speaker |
string | null | Speaker name when the segment is linked to an enrolled speaker, otherwise the diarization speaker label, otherwise null. |
start_time |
number | Segment start time, in seconds. |
end_time |
number | Segment end time, in seconds. |
chromadb_id |
string | null | Vector-store id of the segment embedding, when present. |
{
"analysis_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
"segments": [
{
"id": "9f1c2a7e-3b6d-4e0a-9c2f-1d5a8b7c6e4f",
"text": "Thanks for joining. Let's walk through the proposal.",
"speaker": "Sales Rep",
"start_time": 0.0,
"end_time": 3.2,
"chromadb_id": "7c9e6679-7425-40de-944b-e07fc1f90ae7:0"
}
],
"total": 1
}
curl "https://api.perceive8.com/v1/query/history/7c9e6679-7425-40de-944b-e07fc1f90ae7?limit=500" \
-H "X-API-Key: pk_live_xxxxxxxxxxxx"
Errors
| Status | When |
|---|---|
404 |
No analysis with that id exists in your workspace. |
POST /v1/query/backfill
Embed transcript segments already stored in PostgreSQL into the vector store so they become searchable through POST /v1/query. Run this when transcripts exist in the database but were never embedded — for example historical transcripts processed before embedding was in place. There is no request body.
Any authenticated workspace member can run a backfill; no special role is required. It only embeds segments belonging to the authenticated user — other workspaces and users are never touched. Segments are embedded in batches of 50 with a short pause between batches to respect embedding rate limits.
Response 200 OK
| Field | Type | Description |
|---|---|---|
segments_embedded |
integer | Number of transcript segments embedded. |
{
"segments_embedded": 4213
}
If the backfill takes longer than about 10 seconds, the endpoint instead returns 202 Accepted and the job keeps running in the background:
{
"segments_embedded": 0,
"status": "in_progress"
}
curl -X POST https://api.perceive8.com/v1/query/backfill \
-H "X-API-Key: pk_live_xxxxxxxxxxxx"
Errors
| Status | When |
|---|---|
409 |
A backfill is already in progress. Only one backfill runs at a time. |
502 |
The backfill failed. |
503 |
The query service is not available. |