Join Keys
| From | To | Join field | Notes |
|---|---|---|---|
| Study | Response | link_id | Path param in GET /responses/{link_id}. Single response returns survey = the study’s link_id. |
| Study | Question | study_id | Path param in GET /studies/{study_id}/questions. Uses the link_id value. |
| Question | Answer | discussion_guide_question_id | Question.id = Answer.discussion_guide_question_id |
| Question | TranscriptRow | discussion_guide_question_id | Question.id = TranscriptRow.discussion_guide_question_id |
| Answer | TranscriptRow | answer_id | One answer can have multiple transcript rows (follow-ups where is_followup: true). |
| Question | Concept | concepts | Array on the Question object. concept_id on Answer/TranscriptRow links to Concept.id. Null when the question has no concepts. |
Entity Fields
Study
Returned by List Studies.| Field | Type | Description |
|---|---|---|
id | uuid | Stable study identifier |
link_id | string | URL slug, used as path param for responses and questions |
title | string | Study title |
desc | string | Study description |
created_at | string | UTC timestamp |
Response
Returned by Get Responses. Each response belongs to a study vialink_id.
| Field | Type | Description |
|---|---|---|
id | uuid | Response identifier |
response_number | number | Order within the study |
progress | string | "complete", "in_progress", etc. |
response_duration_seconds | number | Total duration |
quality_score | number | Quality rating |
answers | object | Keyed by label (e.g. "Summary", "Question 1") |
answers_array | Answer[] | Structured answers, joinable to questions and transcript |
attributes | object | URL params passed into the study |
tags | string[] | Keywords |
tagline | string | One-line synthesis |
bullet_summary | string[] | Bullet-point summary |
short_transcript | string | Condensed moderator turns |
created_at | string | UTC timestamp |
updated_at | string | UTC timestamp |
Answer
Nested insideResponse.answers_array.
| Field | Type | Description |
|---|---|---|
answer_id | string | Join key — matches TranscriptRow.answer_id |
discussion_guide_question_id | string | Join key — matches Question.id |
concept_id | string | null | Links to Concept.id when the question involves concept testing |
question | string | Question text |
answer | string | Answer text |
TranscriptRow
Returned by Get Single Response inside thetranscript array.
| Field | Type | Description |
|---|---|---|
moderator | string | Assistant/moderator text |
user | string | Participant text |
discussion_guide_question_id | string | Join key — matches Question.id |
answer_id | string | null | Join key — matches Answer.answer_id. Null for non-question rows (e.g. intro). |
concept_id | string | null | Links to Concept.id |
response_index | number | Zero-based row index |
is_followup | boolean | true when this row is a follow-up to the same question as the previous row |
audio | string | null | Signed URL (~1 hour validity) |
video | object | null | Contains stream_url (HLS) and mp4_url |
Question
Returned by Get Study Questions.| Field | Type | Description |
|---|---|---|
id | string | Join key — referenced as discussion_guide_question_id on answers and transcript rows |
text | string | Question text shown to participants |
type | string | open_ended, multiple_choice, ranking, statement |
question_number | number | Display order |
is_screener | boolean | Whether this is a screener question |
options | string[] | Choices (for multiple_choice and ranking types) |
is_multi_select | boolean | Whether multiple selections are allowed (multiple_choice only) |
concepts | Concept[] | Concept definitions attached to this question |
Concept
Nested insideQuestion.concepts.
| Field | Type | Description |
|---|---|---|
id | string | Referenced by concept_id on Answer and TranscriptRow |
title | string | Concept title |
description | string | Concept description |
media | Media[] | Attached images/videos (type, name, url) |
embed_url | string | null | External embed (e.g. Figma link) |
Traversal Examples
Get all answers for a study, grouped by question
GET /api/public/list_surveys— find the study’slink_idGET /api/public/studies/{link_id}/questions— get all questionsGET /api/public/responses/{link_id}— get all responses- Join each
answers_array[]item to its question usingdiscussion_guide_question_id=Question.id
Match transcript audio/video to specific questions
GET /api/public/responses/{link_id}/{response_id}— get the full transcriptGET /api/public/studies/{link_id}/questions— get question definitions- Each transcript row’s
discussion_guide_question_idtells you which question it belongs to - Use
audioandvideofields on the transcript row to access the media for that exchange
Group transcript rows by answer (including follow-ups)
GET /api/public/responses/{link_id}/{response_id}— get the full transcript- Group transcript rows by
answer_id— rows sharing the sameanswer_idbelong to the same answer, with follow-ups marked byis_followup: true - Cross-reference with
answers_arrayfrom the list endpoint using the sameanswer_idto get the extracted answer text