Accessing Data Models
Learn how to query core data types in the BuildBetter API: Calls (Interviews), Signals (Extractions), and Documents.
Data Access
The BuildBetter GraphQL API organizes data into a few core types that reflect the product’s concepts. The primary ones you’ll likely use are calls, signals, and documents. Under the hood, these correspond to the GraphQL types interview
(for calls), extraction
(for signals), and document
(for documents). This section describes how to query each type, including related data like participants, transcripts, and metadata.
Calls (Interviews)
Calls represent recorded conversations (often meetings or user interviews) that have been ingested into BuildBetter. In the GraphQL API, calls are exposed via the interview
type. You can query a list of calls or a specific call by ID. Key fields on a call include:
id
: The unique identifier of the call (BigInt).name
: A title or name of the call (often an automatically generated name, or one provided by the user).started_at
andcompleted_at
: Timestamps for when the call started and when it ended (if completed).asset_url
andasset_duration_seconds
: Info about the recorded media (e.g., a URL to the audio/video and its duration).type
: The call type or category (for example, demo call, user interview, etc.). This is an object relationship; you can querytype { id name }
to get the type’s name.tags
: Any tags associated with the call (an array relationship). Each tag object has a name and color, accessible viatags { tag { name color } }
.- Participants: The people who participated in the call. Participants are accessible via the
attendees
relationship. Eachattendee
has aperson
object with details. For example, you can queryattendees { person { first_name last_name email avatar_url } }
to get the names and emails of participants. If a participant is a registered user in your organization, theperson
will link to auser
account (you can seeperson.user.id
), otherwise it may just have a name/email from the calendar invite. The attendee record also includes aspeaker
label (an identifier for that speaker in transcript data). - Transcript: BuildBetter automatically transcribes calls. The transcript is available via two relationships:
monologues
: This is an array of transcribed speech segments. Each monologue hastext
(the transcript of that segment),start_sec
andend_sec
(the timestamps in seconds within the call when that segment starts/ends), andspeaker
(which speaker spoke that segment, corresponding to an attendee). Monologues are ordered by time; you can querymonologues(order_by: { start_sec: asc })
to get the full call transcript in chronological order.sentences
: This is a similar array where the transcript may be split into sentence-level segments. Each hastext
and timestamps as well. (In many cases you can rely onmonologues
for the full text with speaker attribution. Thesentences
may be useful for finer-grained analysis.)
You can fetch any subset of these fields in a single query. For example, if you want the call’s basic info, participants, and transcript, you can retrieve id, name, started_at, attendees {...}, monologues {...}
all in one query. Be mindful that the transcript text can be long; if you only need a portion (e.g., the first few lines), you might fetch a limited subset of monologues
or apply a time filter (not shown, but you could filter monologues by time if the schema supports it).
Permissions: When using a user token or an organization API key, you will only see calls that belong to your organization. Each call is associated with an organization_id
internally, and the API enforces that you can only query calls for your org. If you use a shared call API key (for example, a link shared with an external user for one call), you will only have access to that specific call (the API uses a special role shared-object
behind the scenes for this). In practice, just ensure you use the correct API key or token, and the GraphQL queries will return only the calls you’re allowed to see.
Signals (Extractions)
Signals are insights or notable data points extracted from calls (and possibly other sources). In the BuildBetter system, signals are often referred to as extractions. Each extraction corresponds to a specific piece of information identified in a call transcript, such as a highlight, an action item, a user sentiment, a mention of a topic, etc. The GraphQL type for signals is extraction
. Key fields and how to query signals:
id
: Unique identifier for the signal (BigInt).interview_id
: The ID of the call (interview) from which this signal was extracted. Typically you will filter signals by a particular call. For example,extraction(where: { interview_id: { _eq: someCallId } }) { ... }
gives all signals for a given call.summary
: A short summary or title of the signal. This is usually a one-liner or brief description of the insight.context
: A longer context string, often a direct excerpt from the transcript around the moment of this signal. For example, if the signal is a “Pain Point” mentioned by a user, thecontext
might be a sentence or two from the call where the user described the pain point. This helps you understand the signal in its original context.start_sec
/end_sec
: Timestamps in the call recording that delimit where this signal occurred (in seconds from start of call). Using these, you could, for instance, locate the segment in the audio/video or display the time in a player.types
: Signals are categorized by type. Thetypes
field is an array relationship linking the signal to one or more types. Each entry has atype { id name }
object, which might be things like “Pain Point”, “Feature Request”, “Positive Feedback”, etc., depending on how your organization defines signal types. In many cases a signal has exactly one type, but the schema allows multiple.topics
: Similar to types, signals can be associated with topics. Thetopics
field is an array of topics (keywords or themes) relevant to the signal. Each has atopic { id text }
sub-object. For example, a signal might have a topic “Pricing” if the user was talking about pricing concerns.attendee
: This is an object relationship to the call participant (attendee) who spoke the content related to the signal. If the signal is tied to something a specific person said, theattendee
link will let you retrieve that person. For instance, you could queryattendee { person { first_name last_name } }
to get the name of the speaker. (The linking is done via the call ID and a speaker identifier internally.) Not all extractions may have an attendee (for example, if a signal is derived from multiple speakers or from the call metadata), but most conversational signals will.creator
: In some cases, signals can be created or confirmed by users. Thecreator
field points to auser
who created the signal (or who the system associates as responsible). For automatically generated signals, this might be null. If present, you can fetchcreator { person { first_name last_name } }
to see which user added the signal. (This is more relevant if your workflow allows manually adding signals.)
To query signals effectively, you will usually filter by a call. A typical query might look like: “Get all signals for Call X, including their type, topic, and context.” You can also filter by type or other properties. For example, you could ask for only signals of a certain category across all calls, using a filter on types
or a specific extraction_type
. The schema supports complex filters (using _exists
or joining through relationships), although common use-cases involve filtering by call or topic.
As with calls, permissions ensure that you only see signals for calls you have access to. If you query with an organization-scoped API key or user token, the extraction
records returned will automatically be filtered to those belonging to your organization’s calls.
Documents
Documents in BuildBetter are pieces of content that may be generated from calls or created by users. Examples of documents include AI-generated summaries of one or multiple calls, or reports compiled from various signals. The GraphQL type is document
. A document can be thought of as a standalone piece of text/content with associated metadata. Important fields and relationships for documents:
id
: Unique document ID (BigInt).name
: The title or name of the document. This might be a user-provided title or an auto-generated one (e.g., “Summary of September 2025 User Interviews”).content
: The main content of the document. This is typically a large text field (for instance, the full text of a summary or report). When you query this field, you will get the entire content string. It could be a few paragraphs or several pages of text, depending on the document.status
: The status of the document’s generation or processing. This is usually an enum with values likewaiting
,processing
,completed
, orerror
. A newly requested AI summary might beprocessing
, and once done it becomescompleted
. If something went wrong, it might beerror
.created_at
/updated_at
: Timestamps for when the document was created and last updated.creator
: The user who created the document. This is a relation to auser
. You can querycreator { person { first_name last_name } }
to get the name of who initiated or authored the document (for AI-generated content, this is the user who triggered the generation).template
: If the document was created using a specific template (BuildBetter supports document templates for consistent formatting), thetemplate
field provides details. You can get the template’sname
and description viatemplate { name description }
. This may be null if no template was used.permission
: An enum indicating the document’s visibility, e.g.private
orpublic
. Private documents are only accessible to your organization, while public might be shareable via a public link (still requires a valid share key in practice).- Source Data (Input): A document can be derived from one or more calls or even an entire folder of calls. The relationship
input_data
links a document to its source calls or folders. Eachinput_data
entry can have either acall
(interview) or afolder
reference:- If the document was generated from specific calls, you will see one or more
input_data
items with acall
object. For example,input_data { call { id name created_at } }
will list each source call used in making the document (with call ID, name, date). - If the document was generated from a folder (which could imply all calls in that folder were used), then
input_data
might contain afolder
object instead. You can queryinput_data { folder { id name } }
in that case. - The schema ensures an
input_data
entry is either a call or a folder (but not both). Typically, for an “All-hands summary” document that covers multiple calls, you’d see multiplecall
entries ininput_data
.
- If the document was generated from specific calls, you will see one or more
Using these fields, you can fetch a document and understand what it contains and where it came from. For instance, you might query a document’s name
, content
, status
, and then also retrieve the list of calls that were used to generate it via input_data.call
. This lets you display the context, e.g., “This summary was generated from 3 calls (Call A, Call B, Call C)”.
Permissions: Documents belong to an organization and possibly have their own sharing settings. With an organization API key or user token, you will see all documents your org has access to. If you use a shared document API key (for a public/shared link), the API will treat you as a special shared-object
role limited to that single document. In that case, you can only query that document (and its related data). Attempts to query other documents will return no data or permission errors. The API enforces that you cannot access documents outside your scope.