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 and completed_at: Timestamps for when the call started and when it ended (if completed).
  • asset_url and asset_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 query type { 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 via tags { tag { name color } }.
  • Participants: The people who participated in the call. Participants are accessible via the attendees relationship. Each attendee has a person object with details. For example, you can query attendees { 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, the person will link to a user account (you can see person.user.id), otherwise it may just have a name/email from the calendar invite. The attendee record also includes a speaker 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 has text (the transcript of that segment), start_sec and end_sec (the timestamps in seconds within the call when that segment starts/ends), and speaker (which speaker spoke that segment, corresponding to an attendee). Monologues are ordered by time; you can query monologues(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 has text and timestamps as well. (In many cases you can rely on monologues for the full text with speaker attribution. The sentences 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, the context 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. The types field is an array relationship linking the signal to one or more types. Each entry has a type { 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. The topics field is an array of topics (keywords or themes) relevant to the signal. Each has a topic { 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, the attendee link will let you retrieve that person. For instance, you could query attendee { 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. The creator field points to a user who created the signal (or who the system associates as responsible). For automatically generated signals, this might be null. If present, you can fetch creator { 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 like waiting, processing, completed, or error. A newly requested AI summary might be processing, and once done it becomes completed. If something went wrong, it might be error.
  • 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 a user. You can query creator { 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), the template field provides details. You can get the template’s name and description via template { name description }. This may be null if no template was used.
  • permission: An enum indicating the document’s visibility, e.g. private or public. 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. Each input_data entry can have either a call (interview) or a folder reference:
    • If the document was generated from specific calls, you will see one or more input_data items with a call 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 a folder object instead. You can query input_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 multiple call entries in input_data.

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.