> ## Documentation Index
> Fetch the complete documentation index at: https://docs.buildbetter.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Legacy GraphQL Examples

> Legacy GraphQL examples for integrations migrating to the BuildBetter REST API.

The BuildBetter GraphQL API is being deprecated for customer integrations. Use REST for new work and migrate existing GraphQL integrations to REST.

<Warning>
  GraphQL examples on this page are legacy migration reference. Move recording and transcript reads to the [Recordings API](/pages/api/recordings).
</Warning>

## Getting Recent Calls

Retrieve the most recent calls from your workspace with participant information.

<Tabs>
  <Tab title="Query">
    ```graphql theme={null}
    query GetRecentCalls {
      interview(limit: 5, order_by: { started_at: desc }) {
        id
        name
        started_at
        duration_sec
        type {
          name
        }
        attendees {
          person {
            first_name
            last_name
            email
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Response">
    ```json theme={null}
    {
      "data": {
        "interview": [
          {
            "id": 12345,
            "name": "Product Review Meeting",
            "started_at": "2025-01-15T14:00:00Z",
            "duration_sec": 1800,
            "type": {
              "name": "Internal Meeting"
            },
            "attendees": [
              {
                "person": {
                  "first_name": "John",
                  "last_name": "Doe",
                  "email": "john@example.com"
                }
              }
            ]
          }
        ]
      }
    }
    ```
  </Tab>

  <Tab title="Implementation">
    ```javascript theme={null}
    // JavaScript/Node.js example
    const axios = require('axios');

    async function getRecentCalls() {
      const query = `
        query GetRecentCalls {
          interview(limit: 5, order_by: { started_at: desc }) {
            id
            name
            started_at
            attendees {
              person {
                first_name
                last_name
              }
            }
          }
        }
      `;

      const response = await axios.post(
        'https://api.buildbetter.app/graphql',
        { query },
        {
          headers: {
            'Authorization': 'Bearer YOUR_API_KEY',
            'Content-Type': 'application/json'
          }
        }
      );

      return response.data;
    }
    ```
  </Tab>
</Tabs>

## Extracting Call Insights

Get signals and key moments from a specific call.

<Tabs>
  <Tab title="Query">
    ```graphql theme={null}
    query GetCallInsights($callId: bigint!) {
      extraction(
        where: { interview_id: { _eq: $callId } }
        order_by: { start_sec: asc }
      ) {
        id
        summary
        context
        start_sec
        end_sec
        types {
          type {
            name
          }
        }
        topics {
          topic {
            text
          }
        }
        attendee {
          person {
            first_name
            last_name
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Variables">
    ```json theme={null}
    {
      "callId": 12345
    }
    ```
  </Tab>

  <Tab title="Python Implementation">
    ```python theme={null}
    import requests
    import json

    def get_call_insights(call_id):
        url = "https://api.buildbetter.app/graphql"
        
        query = """
        query GetCallInsights($callId: bigint!) {
          extraction(
            where: { interview_id: { _eq: $callId } }
            order_by: { start_sec: asc }
          ) {
            id
            summary
            context
            types {
              type {
                name
              }
            }
          }
        }
        """
        
        variables = {"callId": call_id}
        
        headers = {
            "Authorization": "Bearer YOUR_API_KEY",
            "Content-Type": "application/json"
        }
        
        response = requests.post(
            url,
            json={"query": query, "variables": variables},
            headers=headers
        )
        
        return response.json()

    # Usage
    insights = get_call_insights(12345)
    for signal in insights['data']['extraction']:
        print(f"Signal: {signal['summary']}")
        print(f"Type: {signal['types'][0]['type']['name']}")
    ```
  </Tab>
</Tabs>

## Building a Call Dashboard

Create a comprehensive dashboard showing calls, participants, and key metrics.

<Tabs>
  <Tab title="Dashboard Query">
    ```graphql theme={null}
    query DashboardData($startDate: timestamptz!, $endDate: timestamptz!) {
      # Get calls in date range
      calls: interview(
        where: {
          started_at: { _gte: $startDate, _lte: $endDate }
        }
        order_by: { started_at: desc }
      ) {
        id
        name
        started_at
        duration_sec
        attendee_count: attendees_aggregate {
          aggregate {
            count
          }
        }
        signal_count: extractions_aggregate {
          aggregate {
            count
          }
        }
      }
      
      # Get top participants
      participants: person(
        limit: 10
        order_by: { attendances_aggregate: { count: desc } }
      ) {
        first_name
        last_name
        email
        call_count: attendances_aggregate {
          aggregate {
            count
          }
        }
      }
      
      # Get signal statistics
      signals: extraction_aggregate(
        where: {
          interview: {
            started_at: { _gte: $startDate, _lte: $endDate }
          }
        }
      ) {
        aggregate {
          count
        }
      }
    }
    ```
  </Tab>

  <Tab title="React Component">
    ```jsx theme={null}
    import React, { useEffect, useState } from 'react';
    import { useQuery, gql } from '@apollo/client';

    const DASHBOARD_QUERY = gql`
      query DashboardData($startDate: timestamptz!, $endDate: timestamptz!) {
        calls: interview(
          where: {
            started_at: { _gte: $startDate, _lte: $endDate }
          }
          order_by: { started_at: desc }
        ) {
          id
          name
          started_at
          duration_sec
        }
      }
    `;

    function CallDashboard() {
      const [startDate] = useState(new Date(Date.now() - 7 * 24 * 60 * 60 * 1000));
      const [endDate] = useState(new Date());
      
      const { loading, error, data } = useQuery(DASHBOARD_QUERY, {
        variables: { 
          startDate: startDate.toISOString(),
          endDate: endDate.toISOString()
        }
      });

      if (loading) return <p>Loading...</p>;
      if (error) return <p>Error: {error.message}</p>;

      return (
        <div>
          <h2>Recent Calls</h2>
          <ul>
            {data.calls.map(call => (
              <li key={call.id}>
                {call.name} - {new Date(call.started_at).toLocaleDateString()}
              </li>
            ))}
          </ul>
        </div>
      );
    }
    ```
  </Tab>
</Tabs>

## Searching and Filtering

Find specific calls or content across your workspace.

<Tabs>
  <Tab title="Search Query">
    ```graphql theme={null}
    query SearchCalls(
      $searchTerm: String!
      $participantEmail: String
      $startDate: timestamptz
      $endDate: timestamptz
    ) {
      interview(
        where: {
          _and: [
            { name: { _ilike: $searchTerm } }
            { started_at: { _gte: $startDate } }
            { started_at: { _lte: $endDate } }
            {
              attendees: {
                person: {
                  email: { _eq: $participantEmail }
                }
              }
            }
          ]
        }
        order_by: { started_at: desc }
      ) {
        id
        name
        started_at
        attendees {
          person {
            first_name
            last_name
            email
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Advanced Filter">
    ```graphql theme={null}
    # Find calls with specific signal types
    query CallsWithPainPoints {
      interview(
        where: {
          extractions: {
            types: {
              type: {
                name: { _eq: "Pain Point" }
              }
            }
          }
        }
      ) {
        id
        name
        pain_points: extractions(
          where: {
            types: {
              type: {
                name: { _eq: "Pain Point" }
              }
            }
          }
        ) {
          summary
          context
        }
      }
    }
    ```
  </Tab>
</Tabs>

## Document Generation Status

Monitor AI-generated document creation and status.

<Tabs>
  <Tab title="Document Query">
    ```graphql theme={null}
    query GetDocumentStatus($docId: bigint!) {
      document_by_pk(id: $docId) {
        id
        name
        status
        content
        created_at
        updated_at
        creator {
          person {
            first_name
            last_name
          }
        }
        # Source calls used to generate this document
        input_data {
          call {
            id
            name
            started_at
          }
        }
      }
    }
    ```
  </Tab>

  <Tab title="Polling Implementation">
    ```typescript theme={null}
    // TypeScript implementation with polling
    import { ApolloClient, InMemoryCache, gql } from '@apollo/client';

    class DocumentMonitor {
      private client: ApolloClient<any>;
      
      constructor(apiKey: string) {
        this.client = new ApolloClient({
          uri: 'https://api.buildbetter.app/graphql',
          cache: new InMemoryCache(),
          headers: {
            'Authorization': `Bearer ${apiKey}`
          }
        });
      }
      
      async pollDocumentStatus(
        docId: number,
        onComplete: (doc: any) => void,
        interval: number = 5000
      ): Promise<void> {
        const query = gql`
          query GetDocumentStatus($docId: bigint!) {
            document_by_pk(id: $docId) {
              id
              name
              status
              content
            }
          }
        `;
        
        const checkStatus = async () => {
          const result = await this.client.query({
            query,
            variables: { docId },
            fetchPolicy: 'network-only'
          });
          
          const doc = result.data.document_by_pk;
          
          if (doc.status === 'completed') {
            onComplete(doc);
          } else {
            setTimeout(checkStatus, interval);
          }
        };
        
        await checkStatus();
      }
    }

    // Usage
    const monitor = new DocumentMonitor('YOUR_API_KEY');
    monitor.pollDocumentStatus(12345, (doc) => {
      console.log('Document ready:', doc.name);
      console.log('Content:', doc.content);
    });
    ```
  </Tab>
</Tabs>

## Pagination Patterns

Handle large datasets efficiently with cursor-based or offset pagination.

<Tabs>
  <Tab title="Offset Pagination">
    ```graphql theme={null}
    query GetCallsPaginated($limit: Int!, $offset: Int!) {
      interview(
        limit: $limit
        offset: $offset
        order_by: { started_at: desc }
      ) {
        id
        name
        started_at
      }
      
      # Get total count for pagination controls
      interview_aggregate {
        aggregate {
          count
        }
      }
    }
    ```
  </Tab>

  <Tab title="Implementation">
    ```javascript theme={null}
    class CallPaginator {
      constructor(apiClient, pageSize = 10) {
        this.client = apiClient;
        this.pageSize = pageSize;
        this.currentPage = 0;
      }
      
      async getPage(pageNumber) {
        const offset = pageNumber * this.pageSize;
        
        const query = `
          query GetCallsPaginated($limit: Int!, $offset: Int!) {
            interview(
              limit: $limit
              offset: $offset
              order_by: { started_at: desc }
            ) {
              id
              name
              started_at
            }
            interview_aggregate {
              aggregate {
                count
              }
            }
          }
        `;
        
        const result = await this.client.query({
          query,
          variables: {
            limit: this.pageSize,
            offset
          }
        });
        
        const totalCount = result.data.interview_aggregate.aggregate.count;
        const totalPages = Math.ceil(totalCount / this.pageSize);
        
        return {
          data: result.data.interview,
          pageInfo: {
            currentPage: pageNumber,
            totalPages,
            totalCount,
            hasNext: pageNumber < totalPages - 1,
            hasPrev: pageNumber > 0
          }
        };
      }
    }
    ```
  </Tab>
</Tabs>

## Error Handling

Properly handle errors and edge cases in your GraphQL implementations.

```javascript theme={null}
async function safeGraphQLQuery(query, variables = {}) {
  try {
    const response = await fetch('https://api.buildbetter.app/graphql', {
      method: 'POST',
      headers: {
        'Authorization': 'Bearer YOUR_API_KEY',
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({ query, variables })
    });
    
    const result = await response.json();
    
    // Check for GraphQL errors
    if (result.errors) {
      console.error('GraphQL Errors:', result.errors);
      
      // Handle specific error types
      result.errors.forEach(error => {
        if (error.message.includes('permission denied')) {
          throw new Error('Access denied. Check your API key permissions.');
        }
        if (error.message.includes('not found')) {
          throw new Error('Resource not found.');
        }
      });
      
      throw new Error('GraphQL query failed');
    }
    
    return result.data;
    
  } catch (error) {
    // Handle network errors
    if (error.name === 'NetworkError') {
      console.error('Network error:', error);
      throw new Error('Unable to connect to API');
    }
    
    // Re-throw other errors
    throw error;
  }
}
```

## Tips

* **Treat these examples as legacy** - use REST for new integrations
* **Request only needed fields** - GraphQL returns exactly what you ask for
* **Use pagination** for large datasets to avoid timeouts
* **Store API keys securely** - never expose them in client-side code
* **Test legacy queries first** in a GraphQL playground before changing existing integrations

## Next Steps

<CardGroup>
  <Card title="Recordings REST API" icon="file-audio" href="/pages/api/recordings">
    Move recording and transcript reads to REST
  </Card>

  <Card title="Legacy GraphQL Reference" icon="book" href="/pages/api/graphql-queries">
    Reference legacy GraphQL queries during migration
  </Card>

  <Card title="Authentication Setup" icon="key" href="/pages/api/authentication">
    Learn how to authenticate your API requests
  </Card>
</CardGroup>
