# API Documentation

### Overview

The BoundaryAI API enables you to programmatically import feedback data from any source- support tickets, CRM exports, surveys, chat logs - and leverage AI-powered analysis to extract insights.

#### Core Concepts

Before diving in, understand these key concepts:

| Concept            | Description                                                                         |
| ------------------ | ----------------------------------------------------------------------------------- |
| **Feedback Group** | A container that organizes related data sources (e.g., "Q1 2024 Customer Feedback") |
| **Data Source**    | A collection of feedback within a group (e.g., "Zendesk Tickets", "NPS Survey")     |
| **Question**       | A field within a data source that holds feedback text                               |
| **APS**            | Analysis Points - credits consumed when pushing content for AI analysis             |

#### How It Works

```
1. Create a Feedback Group (or use existing)
         ↓
2. Create a Data Source with Questions
         ↓
3. Publish the Data Source
         ↓
4. Push your feedback content
         ↓
5. BoundaryAI analyzes and extracts insights
```

***

## Authentication

### API Keys

All API requests require an API key passed in the `Authorization` header:

```http
Authorization: Bearer inpk_live_abc123xyz_SbcEpUl9DWuI8IOI-YImkxPNSisaAab7t0goFuliM-4
```

#### Key Format

```
inpk_{environment}_{key_id}_{secret}
```

| Part          | Description                                      |
| ------------- | ------------------------------------------------ |
| `inpk`        | Fixed prefix (Input API Key)                     |
| `environment` | `live` (production) or `test` (no APS deduction) |
| `key_id`      | 10-character unique identifier                   |
| `secret`      | Base64-encoded secret (44 characters)            |

#### Key Permissions

When creating an API key, you choose its permission level:

| Permission | Can Do                                  | Use Case                  |
| ---------- | --------------------------------------- | ------------------------- |
| `push`     | Push content to existing data sources   | Automated import scripts  |
| `create`   | Create feedback groups and data sources | Setup automation          |
| `all`      | Everything                              | Full programmatic control |

#### Getting Your API Key

1. Go to **Integrations** → **API** in your BoundaryAI dashboard
2. Click **Create API Key**
3. Choose a name, environment, and permission level
4. **Save the key immediately** — it's only shown once!

#### Security Notes

* Keys are hashed server-side; we never store the plaintext
* Use `test` environment keys for testing (no APS charges)
* Rotate keys regularly via the dashboard (do not forget to copy after rotating since they also appear only once)

***

## Making Requests

### Base URLs

| Environment   | Base URL                       |
| ------------- | ------------------------------ |
| Europe        | <https://app.boundary-ai.com/> |
| North America | <https://app.boundary-ai.com/> |
| APAC          | Coming soon                    |

### Request Format

All requests must include:

```http
Authorization: Bearer {your_api_key}
Content-Type: application/json
```

### Response Format

#### Success Response

```json
{
  "status": "success",
  "inserted": 3,
  "aps_deducted": 3,
  "question_id": 736,
  "survey_id": 287,
  "survey_series_id": 2
}
```

#### Error Response

```json
{
  "error": {
    "code": "SURVEY_NOT_FOUND",
    "message": "Data source with ID 999 does not exist",
    "details": {}
  }
}
```

### Rate Limiting

Three layers protect the API:

| Layer   | Limit              | Scope                    |
| ------- | ------------------ | ------------------------ |
| Per-Key | 60/min (max = 300) | Individual API key       |
| Per-Org | 1000/min           | All keys in organization |
| Per-IP  | 1000/min           | Fallback protection      |

**Response headers:**

```http
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 58
X-RateLimit-Reset: 1704067200
```

When rate limited, you'll receive HTTP `429` with a `Retry-After` header.

### Idempotency

Prevent duplicate data by including an idempotency key:

```http
Idempotency-Key: import-batch-2024-01-15-001
```

| Scenario                     | Result                                        |
| ---------------------------- | --------------------------------------------- |
| First request                | Executes normally, caches response for 24h    |
| Same key + same payload      | Returns cached response (no duplicate insert) |
| Same key + different payload | Returns HTTP `409` conflict error             |

**Best practice:** Use a unique identifier like `{source}-{date}-{batch}` for each import batch.

***

## Endpoints Reference

### Quick Reference

| Method | Endpoint                          | Description                             | Permission |
| ------ | --------------------------------- | --------------------------------------- | ---------- |
| `GET`  | `/api/input/surveys/list`         | List all feedback groups & data sources | any        |
| `POST` | `/api/input/survey_series/create` | Create a feedback group                 | `create`   |
| `POST` | `/api/input/survey/create`        | Create a data source                    | `create`   |
| `POST` | `/api/input/survey/publish`       | Publish a data source                   | `create`   |
| `POST` | `/api/input/content/push`         | Push content to one question            | `push`     |
| `POST` | `/api/input/content/push/bulk`    | Push content to multiple questions      | `push`     |

***

## List Data Sources

Retrieve all feedback groups and data sources your API key can access. **Run this first** to get the IDs you need for pushing content.

```http
GET /api/input/surveys/list
```

### Query Parameters

| Parameter          | Type    | Description                       |
| ------------------ | ------- | --------------------------------- |
| `survey_series_id` | integer | Filter to specific feedback group |
| `survey_id`        | integer | Filter to specific data source    |

### Response

```json
{
  "org_id": 1,
  "survey_series": [
    {
      "id": 101,
      "name": "Customer Support Logs",
      "surveys": [
        {
          "id": 505,
          "title": "Live Chat Export",
          "description": "Survey description here",
          "mode": "ACCESSIBLE",
          "questions": [
            {
              "id": 888,
              "title": "User Message",
              "type": "long_answer",
              "accepts_text": true
            }
          ]
        }
      ]
    }
  ]
}
```

### Understanding the Response

| Field           | Description                                                     |
| --------------- | --------------------------------------------------------------- |
| `survey_series` | Array of feedback groups                                        |
| `surveys`       | Array of data sources within a group                            |
| `questions`     | Fields available for content                                    |
| `accepts_text`  | **Important!** Only push text to questions where this is `true` |
| `mode`          | `ACCESSIBLE` = published, `EDITING` = draft                     |

### Example

```bash
curl -X GET "https://app.boundary-ai.com/api/input/surveys/list" \
  -H "Authorization: Bearer $API_KEY"
```

***

## Push Content

Push feedback text to a specific question. This is the primary endpoint for importing data.

```http
POST /api/input/content/push
```

### Request Body

```json
{
  "survey_series_id": "123",
  "survey_id": "456",
  "question": {
    "question_id": "789",
    "content": [
      "The checkout process was confusing",
      "Love the new dark mode feature!",
      "App crashes when uploading large files"
    ]
  },
  "source_reference": "zendesk-export-2024-01-15"
}
```

### Parameters

| Field                  | Type   | Required | Description                                  |
| ---------------------- | ------ | -------- | -------------------------------------------- |
| `survey_series_id`     | string | Yes      | Feedback group ID                            |
| `survey_id`            | string | Yes      | Data source ID                               |
| `question.question_id` | string | Yes      | Question ID (must have `accepts_text: true`) |
| `question.content`     | array  | Yes      | Array of feedback strings                    |
| `source_reference`     | string | No       | Your reference for this import batch         |

#### Content Limits

| Limit                   | Value  |
| ----------------------- | ------ |
| Max items per request   | 1,000  |
| Max characters per item | 10,000 |

### Response

```json
{
  "status": "success",
  "inserted": 3,
  "aps_deducted": 3,
  "question_id": 736,
  "survey_id": 287,
  "survey_series_id": 2
}
```

| Field          | Description                         |
| -------------- | ----------------------------------- |
| `inserted`     | Number of new entries added         |
| `duplicates`   | Number of duplicate entries skipped |
| `aps_deducted` | Analysis points consumed            |

### Example: Python

```python
import requests

API_KEY = "inpk_live_xxx_yyy"
BASE_URL = "https://app.boundary-ai.com"

response = requests.post(
    f"{BASE_URL}/api/input/content/push",
    headers={
        "Authorization": f"Bearer {API_KEY}",
        "Content-Type": "application/json"
    },
    json={
        "survey_series_id": "123",
        "survey_id": "456",
        "question": {
            "question_id": "789",
            "content": [
                "Great product, easy to use!",
                "Support team was very helpful",
                "Would recommend to others"
            ]
        },
        "source_reference": "crm-export-2024-01"
    }
)

result = response.json()
print(f"Inserted: {result['inserted']}, APS used: {result['aps_deducted']}")
```

### Example: JavaScript

```javascript
const API_KEY = 'inpk_live_xxx_yyy';
const BASE_URL = 'https://app.boundary-ai.com';

const response = await fetch(`${BASE_URL}/api/input/content/push`, {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${API_KEY}`,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    survey_series_id: "123",
    survey_id: "456",
    question: {
      question_id: "789",
      content: [
        'Great product, easy to use!',
        'Support team was very helpful',
        'Would recommend to others'
      ]
    },
    source_reference: 'crm-export-2024-01'
  })
});

const result = await response.json();
console.log(`Inserted: ${result.inserted}, APS used: ${result.aps_deducted}`);
```

### Example: Curl

```bash
curl -X POST "https://app.boundary-ai.com/api/input/content/push" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: batch-001" \
  -d '{
    "survey_series_id": "123",
    "survey_id": "456",
    "question": {
      "question_id": "789",
      "content": [
        "Great product, easy to use!",
        "Support team was very helpful"
      ]
    }
  }'
```

***

## Bulk Push Content

Push content to multiple questions in a single request. Useful when your data has multiple fields.

```http
POST /api/input/content/push/bulk
```

### Request Body

```json
{
  "survey_series_id": "123",
  "survey_id": "456",
  "questions": [
    {
      "question_id": "789",
      "content": ["Feedback for question 1", "More feedback"]
    },
    {
      "question_id": "790",
      "content": ["Feedback for question 2"]
    }
  ],
  "source_reference": "bulk-import-001"
}
```

### Parameters

| Field                     | Type   | Required | Description                         |
| ------------------------- | ------ | -------- | ----------------------------------- |
| `survey_series_id`        | string | Yes      | Feedback group ID                   |
| `survey_id`               | string | Yes      | Data source ID                      |
| `questions`               | array  | Yes      | Array of question objects (max 100) |
| `questions[].question_id` | string | Yes      | Question ID                         |
| `questions[].content`     | array  | Yes      | Array of feedback strings           |
| `source_reference`        | string | No       | Your reference for this batch       |

### Response

```json
{
  "status": "success",
  "survey_series_id": 2,
  "survey_id": 287,
  "total_inserted": 2,
  "total_aps_deducted": 2,
  "questions": [
    {"question_id": 736, "inserted": 2, "status": "success"}
  ]
}

```

***

## Create Feedback Group

Create a new feedback group to organize related data sources.

```http
POST /api/input/survey_series/create
```

**Required Permission:** `create` or `all`

### Request Body

```json
{
  "name": "Product Feedback 2024"
}
```

### Parameters

| Field  | Type   | Required | Description                   |
| ------ | ------ | -------- | ----------------------------- |
| `name` | string | Yes      | Group name (2-255 characters) |

### Response

```json
{
  "status": "success",
  "created": true,
  "survey_series": {
    "id": 123,
    "name": "Product Feedback 2024"
  }
}
```

> **Note:** If a group with the same name exists, it returns the existing group with `"created": false`.

***

## Create Data Source

Create a new data source with questions within a feedback group.

```http
POST /api/input/survey/create
```

**Required Permission:** `create` or `all`

### Request Body

```json
{
  "survey_series_id": "123",
  "survey_title": "Zendesk Tickets Import",
  "survey_description": "Support tickets from January 2024",
  "questions": [
    {
      "question_title": "Ticket Content",
      "question_type": "DEPTH_TEXT",
      "is_mandatory": true
    },
    {
      "question_title": "Customer Sentiment",
      "question_type": "SCQ",
      "question_options": ["Positive", "Neutral", "Negative"],
      "is_mandatory": false
    }
  ]
}
```

### Parameters

| Field                | Type   | Required | Description                    |
| -------------------- | ------ | -------- | ------------------------------ |
| `survey_series_id`   | string | Yes      | Parent feedback group ID       |
| `survey_title`       | string | Yes      | Data source name (1-100 chars) |
| `survey_description` | string | No       | Description (max 1000 chars)   |
| `questions`          | array  | No       | Array of questions to create   |

### Question Types

| Type         | Aliases        | Description                    | Accepts Text |
| ------------ | -------------- | ------------------------------ | ------------ |
| `DEPTH_TEXT` | `long_answer`  | Long-form text (AI-analyzed)   | ✅ Yes        |
| `TEXT`       | `short_answer` | Short text                     | ✅ Yes        |
| `MCQ`        | `mcq`          | Multiple choice (multi-select) | ❌ No         |
| `SCQ`        | `scq`          | Single choice                  | ❌ No         |
| `RATING`     | `rating`       | 1-5 scale                      | ❌ No         |
| `NPS`        | `nps`          | Net Promoter Score (0-10)      | ❌ No         |

> **Tip:** Use `DEPTH_TEXT` for feedback text you want AI to analyze.

### Response

```json
{
  "status": "success",
  "survey_series_id": 123,
  "survey_id": 456,
  "questions_created": 2,
  "questions": [
    {"id": 789, "title": "Ticket Content", "type": "DEPTH_TEXT"},
    {"id": 790, "title": "Customer Sentiment", "type": "SCQ"}
  ],
  "message": "Survey 'Zendesk Tickets Import' created with 2 question(s)"
}
```

***

## Publish Data Source

Publish a data source to enable data collection and analysis.

```http
POST /api/input/survey/publish
```

**Required Permission:** `create` or `all`

### Request Body

```json
{
  "survey_series_id": 123,
  "survey_id": 456
}
```

### Response

```json
{
  "status": "success",
  "survey_id": 456,
  "survey_series_id": 123,
  "mode": "ACCESSIBLE",
  "message": "Survey published successfully"
}
```

> **Note:** You must publish a data source before you can push content to it.

***

## Webhooks

\
See [Webhooks](/boundaryai-docs/api-and-webhooks/webhooks.md) page

***

## Complete Example

Here's a full workflow: create a feedback group, add a data source, publish it, and push content.

```bash
#!/bin/bash
# Full API workflow example

API_KEY="inpk_live_xxx_yyy"
BASE_URL="https://app.boundary-ai.com"

# Step 1: Create a feedback group
echo "Creating feedback group..."
SERIES_RESPONSE=$(curl -s -X POST "$BASE_URL/api/input/survey_series/create" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"name": "Support Tickets Q1 2024"}')

SERIES_ID=$(echo $SERIES_RESPONSE | jq -r '.survey_series.id')
echo "Created feedback group ID: $SERIES_ID"

# Step 2: Create a data source with a text question
echo "Creating data source..."
SURVEY_RESPONSE=$(curl -s -X POST "$BASE_URL/api/input/survey/create" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{
    \"survey_series_id\": \"$SERIES_ID\",
    \"survey_title\": \"Zendesk Import\",
    \"questions\": [
      {\"question_title\": \"Ticket Content\", \"question_type\": \"DEPTH_TEXT\"}
    ]
  }")

SURVEY_ID=$(echo $SURVEY_RESPONSE | jq -r '.survey_id')
QUESTION_ID=$(echo $SURVEY_RESPONSE | jq -r '.questions[0].id')
echo "Created data source ID: $SURVEY_ID, Question ID: $QUESTION_ID"

# Step 3: Publish the data source
echo "Publishing data source..."
curl -s -X POST "$BASE_URL/api/input/survey/publish" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"survey_series_id\": $SERIES_ID, \"survey_id\": $SURVEY_ID}"

# Step 4: Push feedback content
echo "Pushing content..."
PUSH_RESPONSE=$(curl -s -X POST "$BASE_URL/api/input/content/push" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: zendesk-batch-$(date +%Y%m%d)-001" \
  -d "{
    \"survey_series_id\": \"$SERIES_ID\",
    \"survey_id\": \"$SURVEY_ID\",
    \"question\": {
      \"question_id\": \"$QUESTION_ID\",
      \"content\": [
        \"The checkout process was confusing and I gave up\",
        \"Love the new search feature - so much faster!\",
        \"App crashes every time I try to upload a PDF\",
        \"Customer support resolved my issue within an hour\",
        \"Would be great to have dark mode option\"
      ]
    },
    \"source_reference\": \"zendesk-export-2024-01-15\"
  }")

echo "Push result: $PUSH_RESPONSE"
echo ""
echo "Done! View your feedback in the BoundaryAI dashboard."
```

***

## Support

* **Email:** <hello@boundary-ai.com>
* **Documentation:** [docs.boundary-ai.com](https://docs.boundary-ai.com)
* **Dashboard:** [app.boundary-ai.com](https://app.boundary-ai.com)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://boundaryai.gitbook.io/boundaryai-docs/api-and-webhooks/api-documentation.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
