> ## 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.

# Feedback Ingestion API

> Send customer feedback, surveys, and support data to BuildBetter

Ingest external feedback data into BuildBetter to analyze alongside your calls and documents. This includes support tickets, NPS surveys, Slack messages, and more.

## Quick Start

<Steps>
  <Step title="Create a Feedback Source">
    Define where your feedback comes from (e.g., "Support Tickets", "NPS Survey")
  </Step>

  <Step title="Create or Update People">
    Ensure the person exists in your system
  </Step>

  <Step title="Send Feedback Records">
    Ingest structured feedback with content and metadata
  </Step>
</Steps>

## Authentication

All requests require authentication:

```bash theme={null}
X-BuildBetter-Api-Key: ORGANIZATION_API_KEY
```

## Endpoints

### Create Feedback Source

<Card title="POST /v3/rest/feedback-sources" icon="plus">
  Creates a new feedback source to categorize your data.

  ```bash theme={null}
  POST https://api.buildbetter.app/v3/rest/feedback-sources
  Content-Type: application/json
  X-BuildBetter-Api-Key: ORGANIZATION_API_KEY

  {
    "name": "Customer Support Tickets",
    "type": "api"
  }
  ```

  **Response:**

  ```json theme={null}
  {
    "id": 123,
    "name": "Customer Support Tickets",
    "type": "api",
    "created_at": "2025-01-01T12:00:00Z"
  }
  ```
</Card>

### Create or Update Person

<Card title="PUT /v3/rest/people" icon="user">
  Ensures a person exists before ingesting their feedback.

  ```bash theme={null}
  PUT https://api.buildbetter.app/v3/rest/people
  Content-Type: application/json
  X-BuildBetter-Api-Key: ORGANIZATION_API_KEY

  {
    "first_name": "John",
    "last_name": "Doe",
    "email": "john@example.com",
    "boundary": "external",
    "company": {
      "name": "Example Corp",
      "domain": "example.com"
    }
  }
  ```

  **Response:**

  ```json theme={null}
  {
    "id": 456,
    "first_name": "John",
    "last_name": "Doe",
    "email": "john@example.com",
    "company_id": 789,
    "created_at": "2025-01-01T12:00:00Z"
  }
  ```
</Card>

### Ingest Feedback Record

<Card title="POST /v3/rest/feedback-sources/{id}/records" icon="message">
  Sends structured feedback data to a feedback source.

  ```bash theme={null}
  POST https://api.buildbetter.app/v3/rest/feedback-sources/123/records
  Content-Type: application/json
  X-BuildBetter-Api-Key: ORGANIZATION_API_KEY

  {
    "person_id": 456,
    "display_ts": "2025-01-01T10:30:00Z",
    "external_id": "unique-id-123",
    "fields": [
      {
        "category": "content",
        "type": "string",
        "name": "feedback",
        "value": "Your actual feedback text here"
      },
      {
        "category": "metadata",
        "type": "string",
        "name": "priority",
        "value": "high"
      }
    ]
  }
  ```

  **Response:**

  ```json theme={null}
  {
    "id": 789,
    "person_id": 456,
    "feedback_source_id": 123,
    "display_ts": "2025-01-01T10:30:00Z",
    "external_id": "unique-id-123",
    "created_at": "2025-01-01T10:30:00Z"
  }
  ```
</Card>

## Field Structure

### Categories

* **`content`** - The actual feedback (comments, descriptions, messages)
* **`created_at`** - Timestamp fields
* **`identifier`** - External identifiers and references
* **`identity`** - User or entity identification fields
* **`metadata`** - Additional context (priority, tags, channel, etc.)

### Types

* **`boolean`** - True/false values
* **`date`** - Date only values
* **`datetime`** - Date and time values
* **`float`** - Decimal numeric values
* **`integer`** - Whole number values
* **`json`** - Structured JSON data
* **`string`** - Text content

### Example Field

```json theme={null}
{
  "category": "content",
  "type": "string",
  "name": "customer_comment",
  "value": "The new dashboard is fantastic!"
}
```

## Implementation Examples

<Tabs>
  <Tab title="Support Tickets">
    ```bash theme={null}
    curl -X POST https://api.buildbetter.app/v3/rest/feedback-sources/123/records \
      -H "X-BuildBetter-Api-Key: ORGANIZATION_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "person_id": 456,
        "display_ts": "2025-01-01T10:30:00Z",
        "external_id": "ticket-789",
        "fields": [
          {
            "category": "content",
            "type": "string",
            "name": "subject",
            "value": "Cannot log into mobile app"
          },
          {
            "category": "content",
            "type": "string",
            "name": "description",
            "value": "Face ID authentication is failing on iOS"
          },
          {
            "category": "metadata",
            "type": "string",
            "name": "priority",
            "value": "high"
          },
          {
            "category": "metadata",
            "type": "string",
            "name": "product_area",
            "value": "mobile_auth"
          }
        ]
      }'
    ```
  </Tab>

  <Tab title="NPS Survey">
    ```bash theme={null}
    curl -X POST https://api.buildbetter.app/v3/rest/feedback-sources/124/records \
      -H "X-BuildBetter-Api-Key: ORGANIZATION_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "person_id": 456,
        "display_ts": "2025-01-01T14:00:00Z",
        "external_id": "nps-2025-q1-456",
        "fields": [
          {
            "category": "content",
            "type": "integer",
            "name": "nps_score",
            "value": 9
          },
          {
            "category": "content",
            "type": "string",
            "name": "feedback",
            "value": "Love the new features!"
          },
          {
            "category": "metadata",
            "type": "string",
            "name": "survey_type",
            "value": "quarterly_nps"
          }
        ]
      }'
    ```
  </Tab>

  <Tab title="Slack Feedback">
    ```bash theme={null}
    curl -X POST https://api.buildbetter.app/v3/rest/feedback-sources/125/records \
      -H "X-BuildBetter-Api-Key: ORGANIZATION_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "person_id": 789,
        "display_ts": "2025-01-01T16:45:00Z",
        "external_id": "slack-msg-abc123",
        "fields": [
          {
            "category": "content",
            "type": "string",
            "name": "message",
            "value": "The API is really slow today"
          },
          {
            "category": "metadata",
            "type": "string",
            "name": "channel",
            "value": "#product-feedback"
          },
          {
            "category": "metadata",
            "type": "string",
            "name": "urgency",
            "value": "medium"
          }
        ]
      }'
    ```
  </Tab>
</Tabs>

## Best Practices

* **Use external\_id** to prevent duplicate records
* **Set display\_ts** to the original timestamp when the feedback was created
* **Validate data** before sending to avoid errors
* **Use snake\_case** and descriptive field names for consistency
* **Include relevant metadata** for better filtering and analysis

## Error Handling

Common error responses and how to handle them:

<AccordionGroup>
  <Accordion title="400 Bad Request">
    **Invalid request format or missing required fields**

    Check that:

    * All required fields are present
    * JSON is properly formatted
    * Field types match expected values
  </Accordion>

  <Accordion title="401 Unauthorized">
    **Invalid or missing API key**

    Ensure:

    * API key is included in X-BuildBetter-Api-Key header
    * Key format is correct
    * API key has necessary permissions
  </Accordion>

  <Accordion title="404 Not Found">
    **Feedback source or person not found**

    Verify:

    * Feedback source ID exists
    * Person ID is valid (if provided)
    * You have access to the resource
  </Accordion>

  <Accordion title="409 Conflict">
    **Duplicate external\_id detected**

    Resolution:

    * Use a unique external\_id
    * Check if record already exists
    * Update existing record if needed
  </Accordion>
</AccordionGroup>

## Rate Limits

* **Requests per minute:** 100
* **Records per request:** 1
* **Field size limit:** 10KB per field value

## Next Steps

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

  <Card title="Explore Webhooks" icon="webhook" href="/pages/api/webhooks">
    Set up real-time notifications for feedback events
  </Card>
</CardGroup>
