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

# API Reference

> Complete endpoint documentation for the Haystack API

## Overview

The Haystack API provides programmatic access to all content management, media processing, search, and analytics features. This reference documents all available endpoints with request/response schemas.

## Base URLs

Haystack provides two APIs with different base URLs:

### Private API (Authenticated Endpoints)

All authenticated endpoints (content management, media, analytics) use:

```
https://api.thehaystack.ai/v2/haystack
```

### Search API (Public, No Authentication)

The search endpoint uses a church-specific base URL:

```
https://{your-church-shortname}.thehaystack.ai/api
```

To find your Search API base URL:

1. Log in to your [Haystack Dashboard](https://app.thehaystack.ai)
2. Navigate to **Developer** → **API**
3. Copy your Search API Base URL from the Search API section

## Authentication

Most endpoints require Bearer token authentication. Include your API token in the `Authorization` header:

```bash theme={null}
Authorization: Bearer YOUR_API_TOKEN
```

<Warning>
  **Important**: The [Search endpoint](/api-reference/endpoints/search) does NOT require authentication and should be called without an API token from public-facing applications. See the [Authentication guide](/authentication#endpoints-that-dont-require-authentication) for details.
</Warning>

See the [Authentication guide](/authentication) for complete details on obtaining and managing API tokens.

## API Structure

The Haystack API is organized into the following resource groups:

### Content Management

<CardGroup cols={2}>
  <Card title="Items" icon="file">
    Create, read, update, and delete content items
  </Card>

  <Card title="Collections" icon="folder">
    Organize items into top-level collections
  </Card>

  <Card title="Speakers" icon="user">
    Manage people who deliver content
  </Card>

  <Card title="Topics" icon="tags">
    Tag content with topical categories
  </Card>
</CardGroup>

### Media

<CardGroup cols={2}>
  <Card title="Media Assets" icon="video">
    Upload and manage video/audio files
  </Card>
</CardGroup>

### Discovery

<CardGroup cols={2}>
  <Card title="Search" icon="magnifying-glass">
    Semantic search across content
  </Card>
</CardGroup>

### Analytics

<CardGroup cols={2}>
  <Card title="Logging" icon="chart-line">
    Track user interactions and events
  </Card>
</CardGroup>

## Request Format

### HTTP Methods

* `GET` - Retrieve resources
* `POST` - Create new resources
* `PATCH` - Update existing resources
* `DELETE` - Remove resources

### Content Type

All `POST` and `PATCH` requests should include:

```bash theme={null}
Content-Type: application/json
```

<Note>
  Media file uploads use a two-step process: first create a media asset via the API to receive a signed upload URL, then PUT the file directly to that URL. See the [Media Management guide](/concepts/media-management) for details.
</Note>

### Query Parameters

Use query parameters for filtering, sorting, and pagination:

```bash theme={null}
GET /items?collectionId=1&status=published&_orderBy[]=date,DESC&_limit=20&_offset=0
```

**Common parameters:**

* `_limit` - Maximum number of records to return (default: 50, max: 100)
* `_offset` - Number of records to skip for pagination (default: 0)
* `_orderBy` - Sort order as array of strings in format 'fieldName,direction' (e.g., 'title,ASC')
* `_expand` - Related entities to include in the response (can specify multiple)

## Response Format

### Success Response

Successful requests return a JSON object with the requested data:

```json theme={null}
{
  "item": {
    "id": 42,
    "title": "Example Item",
    "date": "2025-01-15"
  }
}
```

List endpoints include pagination metadata:

```json theme={null}
{
  "items": [...],
  "limit": 50,
  "offset": 0,
  "page": 0,
  "totalRecords": 150,
  "totalPages": 3,
  "hasMore": true
}
```

### Error Response

Errors return a standardized format:

```json theme={null}
{
  "result": "error",
  "error": {
    "type": "ValidationError",
    "message": "Title is required"
  }
}
```

## HTTP Status Codes

| Code  | Meaning                                  |
| ----- | ---------------------------------------- |
| `200` | Success                                  |
| `201` | Created                                  |
| `400` | Bad Request - Invalid parameters         |
| `401` | Unauthorized - Invalid or missing token  |
| `403` | Forbidden - Insufficient permissions     |
| `404` | Not Found - Resource doesn't exist       |
| `422` | Unprocessable Entity - Validation failed |
| `500` | Internal Server Error                    |

## Pagination

List endpoints support pagination using `_limit` and `_offset`:

```javascript theme={null}
// Get 50 items starting from offset 50 (second page)
const response = await fetch(
  `${API_URL}/items?_limit=50&_offset=50`,
  {
    headers: {
      'Authorization': `Bearer ${API_TOKEN}`
    }
  }
);

const data = await response.json();
console.log(`Page ${data.page + 1} of ${data.totalPages}`);
console.log(`Showing ${data.items.length} of ${data.totalRecords} total items`);
console.log(`Has more: ${data.hasMore}`);
```

## Expanding Related Data

Use `_expand` to include related data in a single request:

```bash theme={null}
# Get item with related data
GET /items/42?_expand[]=collection&_expand[]=series&_expand[]=speakers&_expand[]=mediaAssets
```

**Available expansions:**

* Items: `collection`, `series`, `speakers`, `mediaAssets`, `scriptures`
* Series: `collection`, `items`
* Collections: `items`, `series`

## Filtering

Most list endpoints support filtering by fields:

```bash theme={null}
# Filter items by multiple criteria
GET /items?collectionId=1&seriesId=5&status=published

# Using filter operators
GET /items?date.gt=2025-01-01&status.ne=draft
```

**Available filter operators:**

* No operator - Exact match (e.g., `collectionId=1`)
* `.eq` - Equal to (e.g., `status.eq=published`)
* `.ne` - Not equal to (e.g., `status.ne=draft`)
* `.in` - In array (e.g., `id.in=1,2,3`)
* `.lt` - Less than (e.g., `date.lt=2025-01-01`)
* `.le` - Less than or equal
* `.gt` - Greater than
* `.ge` - Greater than or equal
* `.bt` - Between two values (e.g., `date.bt=2025-01-01,2025-12-31`)
* `.nl` - Is null (e.g., `seriesId.nl=true`)
* `.like` - Pattern matching (e.g., `title.like=%prayer%`)

## Sorting

Sort results using `_orderBy`:

```bash theme={null}
# Get newest items first
GET /items?_orderBy[]=date,DESC

# Get topics by display order
GET /topics?_orderBy[]=displayOrder,ASC

# Multiple sort fields
GET /items?_orderBy[]=date,DESC&_orderBy[]=title,ASC
```
