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

# Search Content

> Semantic search across sermons, scriptures, and series. By default returns all results in a single JSON response. When `stream=true`, returns a text/event-stream with these message types:

- `results` — full results payload (same shape as the non-stream response)
- `headline` — streaming AI headline (`{headline: string}` appended incrementally)
- `overview` — streaming AI overview (`{overview: string}` appended incrementally)
- `complete` — final message; stream closes
- `error` — error event; stream closes

<Warning>
  **No Authentication Required**: This endpoint does NOT require authentication. Never include your API token when calling this endpoint, especially from client-side JavaScript, as this would expose your credentials to all users.
</Warning>

<Note>
  **Using "Try It Out"**: This endpoint requires a church-specific base URL. To test this endpoint:

  1. Click the server dropdown and select "Your church-specific Search API"
  2. Replace `{churchShortname}` with your actual church shortname
  3. Find your shortname in the [Haystack Dashboard](https://app.thehaystack.ai) under **Developer** → **API**

  Example: If your Search API URL is `https://gracechurch.thehaystack.ai/api`, your shortname is `gracechurch`.
</Note>

## Response Format

The search endpoint supports two response formats:

### Standard JSON Response (Default)

Fast, simple response with search results only. Best for most use cases.

<CodeGroup>
  ```javascript JavaScript theme={null}
  const SEARCH_URL = 'https://your-church-name.thehaystack.ai/api';

  const response = await fetch(
    `${SEARCH_URL}/haystack/search?q=${encodeURIComponent('prayer')}`
  );

  const data = await response.json();
  // Returns: { query, queryAnalyticsId, items, scriptures, series }
  console.log('Found', data.items.length, 'items');
  ```

  ```python Python theme={null}
  import requests

  SEARCH_URL = 'https://your-church-name.thehaystack.ai/api'

  response = requests.get(
      f'{SEARCH_URL}/haystack/search',
      params={'q': 'prayer'}
  )

  data = response.json()
  print(f"Found {len(data['items'])} items")
  ```

  ```bash cURL theme={null}
  curl "https://your-church-name.thehaystack.ai/api/haystack/search?q=prayer"
  ```
</CodeGroup>

### Streaming Response with AI Overview (Advanced)

For an AI-generated overview of results, add `?stream=true` to receive a Server-Sent Events stream. This feature is best suited for advanced integrations that need real-time AI summaries.

<Accordion title="Server-Sent Events Implementation">
  **Event Types:**

  * `results`: Search results (same structure as JSON response)
  * `overview`: Chunks of AI-generated summary as they're generated
  * `complete`: Stream finished successfully
  * `error`: An error occurred

  **Example Implementations:**

  <CodeGroup>
    ```javascript JavaScript (Browser) theme={null}
    const SEARCH_URL = 'https://your-church-name.thehaystack.ai/api';

    const eventSource = new EventSource(
      `${SEARCH_URL}/haystack/search?q=prayer&stream=true`
    );

    let overviewText = '';

    eventSource.addEventListener('results', (event) => {
      const message = JSON.parse(event.data);
      console.log('Results:', message.data);
    });

    eventSource.addEventListener('overview', (event) => {
      const message = JSON.parse(event.data);
      overviewText += message.data.overview;
      console.log('Overview chunk:', message.data.overview);
    });

    eventSource.addEventListener('complete', () => {
      console.log('Complete overview:', overviewText);
      eventSource.close();
    });

    eventSource.addEventListener('error', (event) => {
      console.error('Error:', JSON.parse(event.data).error);
      eventSource.close();
    });
    ```

    ```python Python theme={null}
    import json
    import sseclient  # pip install sseclient-py
    import requests

    SEARCH_URL = 'https://your-church-name.thehaystack.ai/api'

    response = requests.get(
        f'{SEARCH_URL}/haystack/search',
        params={'q': 'prayer', 'stream': 'true'},
        stream=True
    )

    client = sseclient.SSEClient(response)
    overview_text = ''

    for event in client.events():
        message = json.loads(event.data)

        if message['type'] == 'results':
            print(f"Found {len(message['data']['items'])} items")
        elif message['type'] == 'overview':
            overview_text += message['data']['overview']
            print('Overview chunk received')
        elif message['type'] == 'complete':
            print(f'Complete overview: {overview_text}')
            break
        elif message['type'] == 'error':
            print(f"Error: {message['error']}")
            break
    ```

    ```php PHP theme={null}
    <?php
    // Using https://github.com/mpociot/php-sse-client
    require 'vendor/autoload.php';

    use Mpociot\SSE\Client;

    $searchUrl = 'https://your-church-name.thehaystack.ai/api';
    $client = new Client("{$searchUrl}/haystack/search?q=prayer&stream=true");

    $overviewText = '';

    $client->on('message', function($event, $data) use (&$overviewText) {
        $message = json_decode($data, true);

        switch ($message['type']) {
            case 'results':
                echo "Found " . count($message['data']['items']) . " items\n";
                break;
            case 'overview':
                $overviewText .= $message['data']['overview'];
                echo "Overview chunk received\n";
                break;
            case 'complete':
                echo "Complete overview: {$overviewText}\n";
                break;
            case 'error':
                echo "Error: {$message['error']}\n";
                break;
        }
    });

    $client->listen();
    ?>
    ```

    ```ruby Ruby theme={null}
    # Using https://github.com/Tonkpils/celluloid-eventsource
    require 'celluloid/eventsource'
    require 'json'

    search_url = 'https://your-church-name.thehaystack.ai/api'
    url = "#{search_url}/haystack/search?q=prayer&stream=true"

    overview_text = ''

    source = Celluloid::EventSource.new(url)

    source.on_message do |raw_message|
      message = JSON.parse(raw_message)

      case message['type']
      when 'results'
        puts "Found #{message['data']['items'].length} items"
      when 'overview'
        overview_text += message['data']['overview']
        puts 'Overview chunk received'
      when 'complete'
        puts "Complete overview: #{overview_text}"
        source.close
      when 'error'
        puts "Error: #{message['error']}"
        source.close
      end
    end
    ```

    ```bash cURL theme={null}
    # Stream SSE events to console
    curl -N "https://your-church-name.thehaystack.ai/api/haystack/search?q=prayer&stream=true"
    ```
  </CodeGroup>

  **Popular SSE Libraries:**

  * **Python:** `sseclient-py`, `aiohttp-sse-client`
  * **PHP:** `mpociot/php-sse-client`, `artax/sse`
  * **Ruby:** `celluloid-eventsource`, `sse-client`
  * **Node.js:** `eventsource`, built-in `fetch` with stream handling
  * **Go:** `r3labs/sse`, standard `http` package
</Accordion>


## OpenAPI

````yaml GET /search
openapi: 3.1.0
info:
  title: Haystack API
  description: Content management and semantic search API for Haystack
  version: 2.0.0
  contact:
    name: Haystack Support
    email: support@thehaystack.ai
    url: https://thehaystack.ai
servers:
  - url: https://api.thehaystack.ai/v2/haystack
    description: Production server
security:
  - bearerAuth: []
tags:
  - name: Items
    description: Content item management
  - name: Collections
    description: Top-level content organization
  - name: Series
    description: Multi-part content grouping
  - name: Speakers
    description: Content presenter management
  - name: Media
    description: Video and audio asset management
  - name: Search
    description: Semantic content search
  - name: Analytics
    description: Usage statistics and metrics
  - name: Resources
    description: Attach supplementary files, links, and videos to items
  - name: Scriptures
    description: Attach Bible references to items
  - name: Chapters
    description: Time-based chapter markers on media assets
  - name: Stats
    description: Analytics and reporting
  - name: Frontend
    description: Public frontend configuration
paths:
  /search:
    get:
      tags:
        - Search
      summary: Search content
      description: >-
        Semantic search across sermons, scriptures, and series. By default
        returns all results in a single JSON response. When `stream=true`,
        returns a text/event-stream with these message types:


        - `results` — full results payload (same shape as the non-stream
        response)

        - `headline` — streaming AI headline (`{headline: string}` appended
        incrementally)

        - `overview` — streaming AI overview (`{overview: string}` appended
        incrementally)

        - `complete` — final message; stream closes

        - `error` — error event; stream closes
      parameters:
        - name: q
          in: query
          required: true
          schema:
            type: string
          description: Natural-language search query
        - name: surface
          in: query
          required: true
          schema:
            type: string
            enum:
              - embed
              - connect
              - console
        - name: embedToken
          in: query
          required: false
          schema:
            type: string
          description: Required when surface=embed
        - name: collectionId
          in: query
          required: false
          schema:
            type: integer
          description: Scope search to a single collection
        - name: stream
          in: query
          required: false
          schema:
            type: boolean
          description: >-
            When true, responds with Server-Sent Events streaming the AI
            overview as it is generated
        - name: overviewFormat
          in: query
          required: false
          schema:
            type: string
          description: Format hint for the AI overview
      responses:
        '200':
          description: >-
            Search results. Returns JSON by default, or Server-Sent Events
            stream when stream=true.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SearchResponse'
            text/event-stream:
              schema:
                type: string
                description: >-
                  Streaming response with AI overview (requires stream=true).
                  Returns Server-Sent Events with types: 'results', 'overview',
                  'complete', or 'error'.
                example: >+
                  data:
                  {"type":"results","data":{"query":"prayer","queryAnalyticsId":"abc123","items":[...],"scriptures":[],"series":[]}}


                  data: {"type":"overview","data":{"overview":"Based on your
                  search..."}}


                  data: {"type":"complete"}

      security: []
      servers:
        - url: https://{churchShortname}.thehaystack.ai/api/haystack
          description: Your church-specific Search API
          variables:
            churchShortname:
              default: your-church-name
              description: >-
                Your church's unique shortname. Find this in the Haystack
                Dashboard under Developer → API.
components:
  schemas:
    SearchResponse:
      type: object
      properties:
        query:
          type: string
        queryAnalyticsId:
          type: string
        items:
          type: array
          items:
            $ref: '#/components/schemas/SearchItemResult'
        scriptures:
          type: array
          items:
            $ref: '#/components/schemas/SearchScriptureResult'
        series:
          type: array
          items:
            $ref: '#/components/schemas/SearchSeriesResult'
        itemDescriptor:
          type: string
          enum:
            - sermon
            - message
            - teaching
            - episode
          description: Descriptor inherited from the searched collection
    SearchItemResult:
      type: object
      properties:
        item:
          $ref: '#/components/schemas/Item'
        score:
          type: number
          description: Relevance score (0-1)
        highlights:
          type: array
          items:
            $ref: '#/components/schemas/Highlight'
    SearchScriptureResult:
      type: object
      properties:
        book:
          type: string
          example: matthew
        bookName:
          type: string
          example: Matthew
        chapter:
          type: integer
        numItems:
          type: integer
          description: Number of items referencing this scripture
    SearchSeriesResult:
      type: object
      properties:
        series:
          $ref: '#/components/schemas/Series'
        numItems:
          type: integer
          description: Number of items in this series
        linkedItemUrlSlug:
          type: string
          description: URL slug of the first item in the series (for linking)
    Item:
      type: object
      properties:
        id:
          type: integer
        title:
          type: string
          example: The Power of Prayer
        subTitle:
          type: string
          nullable: true
        description:
          type: string
          nullable: true
        shortDescription:
          type: string
          nullable: true
        date:
          type: string
          format: date
          example: '2025-01-15'
        collectionId:
          type: integer
        seriesId:
          type: integer
          nullable: true
        orderInSeries:
          type: integer
          nullable: true
        urlSlug:
          type: string
          nullable: true
        durationSecs:
          type: integer
          nullable: true
          description: Duration of the item's media in seconds
        status:
          type: string
          enum:
            - draft
            - queued
            - processing
            - ready
            - publishing
            - published
            - unpublishing
            - unpublished
            - actionRequired
            - error
        wizardStep:
          type: string
          enum:
            - basicDetails
            - artwork
            - media
            - processing
            - finalize
          description: Current step in the item creation wizard
        publishedDate:
          type: string
          format: date-time
          nullable: true
        autoPublish:
          type: boolean
          nullable: true
        squareImgUrl:
          type: string
          nullable: true
          description: URL for the square (1:1) artwork image
        wideImgUrl:
          type: string
          nullable: true
          description: URL for the wide (16:9) artwork image
        ultraWideImgUrl:
          type: string
          nullable: true
          description: URL for the ultra-wide (2.77:1) artwork image
        verticalImgUrl:
          type: string
          nullable: true
          description: URL for the vertical (2:3) artwork image
        entryDate:
          type: string
          format: date-time
          description: Date the item was created
        collection:
          $ref: '#/components/schemas/Collection'
          description: Included when _expand contains 'collection'
        series:
          $ref: '#/components/schemas/Series'
          nullable: true
          description: Included when _expand contains 'series'
        speakers:
          type: array
          items:
            $ref: '#/components/schemas/Speaker'
          description: Included when _expand contains 'speakers'
        scriptures:
          type: array
          items:
            $ref: '#/components/schemas/ItemScripture'
          description: Included when _expand contains 'scriptures'
        mediaAssets:
          type: array
          items:
            $ref: '#/components/schemas/MediaAsset'
          description: Included when _expand contains 'mediaAssets'
        resources:
          type: array
          items:
            $ref: '#/components/schemas/ItemResource'
          description: Included when _expand contains 'resources'
        suggestedDescription:
          type: string
          nullable: true
          description: AI-generated description awaiting acceptance
        suggestedShortDescription:
          type: string
          nullable: true
        errorMessage:
          type: string
          nullable: true
          description: Set when status is `error` or `actionRequired`
        indexedMediaAssetId:
          type: integer
          nullable: true
          description: The media asset whose transcript was embedded for search
        autoAcceptScriptures:
          type: boolean
          nullable: true
          description: Auto-accept AI-suggested scriptures without review
        autoAcceptMediaChapters:
          type: boolean
          nullable: true
        transcriptUrl:
          type: string
          nullable: true
          description: CDN URL for the raw transcript JSON
        topics:
          type: array
          items:
            $ref: '#/components/schemas/Topic'
          description: Included when _expand contains 'topics'
        squareImgMetadata:
          type: object
          additionalProperties: true
          nullable: true
        wideImgMetadata:
          type: object
          additionalProperties: true
          nullable: true
        ultraWideImgMetadata:
          type: object
          additionalProperties: true
          nullable: true
        verticalImgMetadata:
          type: object
          additionalProperties: true
          nullable: true
    Highlight:
      type: object
      properties:
        transcript:
          type: string
        startMs:
          type: integer
          description: Start time in milliseconds
        endMs:
          type: integer
          description: End time in milliseconds
        score:
          type: number
        thumbnailUrl:
          type: string
          nullable: true
    Series:
      type: object
      properties:
        id:
          type: integer
        title:
          type: string
          example: The Gospel of John
        subTitle:
          type: string
          nullable: true
        collectionId:
          type: integer
        description:
          type: string
          nullable: true
        shortDescription:
          type: string
          nullable: true
        sortOrder:
          type: integer
        itemSortDirection:
          type: string
          enum:
            - ASC
            - DESC
          default: DESC
        showItemOrderInSeries:
          type: boolean
          default: true
        urlSlug:
          type: string
          nullable: true
        colorHex:
          type: string
          nullable: true
          example: '#FF5733'
        squareImgUrl:
          type: string
          nullable: true
          description: Full URL to the square artwork (1:1 aspect ratio)
        wideImgUrl:
          type: string
          nullable: true
          description: Full URL to the wide artwork (16:9 aspect ratio)
        ultraWideImgUrl:
          type: string
          nullable: true
          description: Full URL to the ultra-wide artwork (2.77:1 aspect ratio)
        published:
          type: boolean
          nullable: true
        verticalImgUrl:
          type: string
          nullable: true
        squareImgMetadata:
          type: object
          additionalProperties: true
          nullable: true
        wideImgMetadata:
          type: object
          additionalProperties: true
          nullable: true
        ultraWideImgMetadata:
          type: object
          additionalProperties: true
          nullable: true
        verticalImgMetadata:
          type: object
          additionalProperties: true
          nullable: true
        items:
          type: array
          items:
            $ref: '#/components/schemas/Item'
          description: Included when _expand contains 'items'
        collection:
          allOf:
            - $ref: '#/components/schemas/Collection'
          nullable: true
          description: Included when _expand contains 'collection'
    Collection:
      type: object
      properties:
        id:
          type: integer
          example: 1
        name:
          type: string
          example: Sunday Sermons
        itemDescriptor:
          type: string
          enum:
            - sermon
            - message
            - teaching
            - episode
        contentFormat:
          type: string
          enum:
            - sermon
            - interview
          description: Shape of content in this collection
        fullService:
          type: boolean
          description: True if items are full services (not just a single sermon)
          default: false
        variantTypes:
          type: array
          items:
            $ref: '#/components/schemas/MediaVariantType'
          description: Included when _expand contains 'variantTypes'
    Speaker:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
          example: Pastor John Smith
        bio:
          type: string
          nullable: true
        imageUrl:
          type: string
          nullable: true
          description: Full URL to the speaker's image
        imageFilename:
          type: string
          nullable: true
          description: Raw filename; clients should use `imageUrl` instead
        itemCount:
          type: integer
          nullable: true
          description: >-
            Item count for this speaker; populated when sorted by
            `_orderBy=itemCount` or expanded with `_expand=items`
    ItemScripture:
      type: object
      properties:
        id:
          type: integer
        itemId:
          type: integer
        book:
          type: string
          description: Bible book code (e.g., 'GEN', 'MAT', 'REV')
        bookName:
          type: string
          description: Full name of the Bible book
          example: Matthew
        chapter:
          type: integer
        verseStart:
          type: integer
        verseEnd:
          type: integer
        keyVerse:
          type: boolean
          nullable: true
          description: Whether this is a key scripture for the item
        suggested:
          type: boolean
          nullable: true
          description: Whether this scripture was AI-suggested
        accepted:
          type: boolean
          nullable: true
          description: Whether a suggested scripture has been accepted
        displayOrder:
          type: integer
          nullable: true
        citation:
          type: string
          description: Formatted citation string
          example: Matthew 5:1-12
        hidden:
          type: boolean
          description: >-
            True if scripture is suggested but not accepted (and not a key
            verse)
    MediaAsset:
      type: object
      properties:
        id:
          type: integer
        itemId:
          type: integer
        item:
          allOf:
            - $ref: '#/components/schemas/Item'
          nullable: true
          description: Included when _expand contains 'item'
        contentType:
          type: string
          enum:
            - audio
            - video
        mimeType:
          type: string
          nullable: true
        variantTypeId:
          type: integer
        variantType:
          allOf:
            - $ref: '#/components/schemas/MediaVariantType'
          nullable: true
          description: Included when _expand contains 'variantType'
        fileSizeBytes:
          type: integer
          nullable: true
        durationSecs:
          type: integer
          nullable: true
        bitrate:
          type: integer
          nullable: true
        videoWidth:
          type: integer
          nullable: true
        videoHeight:
          type: integer
          nullable: true
        filename:
          type: string
          nullable: true
          description: Raw storage key; use `url` to link to the file
        originalFilename:
          type: string
          nullable: true
        externalPlatform:
          type: string
          enum:
            - youtube
            - vimeo
          nullable: true
        externalPlatformId:
          type: string
          nullable: true
        muxAssetId:
          type: string
          nullable: true
        muxPlaybackId:
          type: string
          nullable: true
        status:
          type: string
          enum:
            - created
            - uploaded
            - processing
            - ready
            - error
        url:
          type: string
          nullable: true
          description: Public CDN URL for the asset
        downloadUrl:
          type: string
          nullable: true
          description: Download URL for the original file
        chapters:
          type: array
          items:
            $ref: '#/components/schemas/MediaChapter'
          description: Included when _expand contains 'chapters'
        entryDate:
          type: string
          format: date-time
    ItemResource:
      type: object
      properties:
        id:
          type: integer
        itemId:
          type: integer
        title:
          type: string
        subTitle:
          type: string
          nullable: true
        description:
          type: string
          nullable: true
        resourceTypeId:
          type: integer
          nullable: true
        displayOrder:
          type: integer
          nullable: true
        contentType:
          type: string
          enum:
            - file
            - link
            - video
        fileMimeType:
          type: string
          nullable: true
        fileSizeBytes:
          type: integer
          nullable: true
        externalPlatform:
          type: string
          enum:
            - youtube
            - vimeo
          nullable: true
        externalPlatformId:
          type: string
          nullable: true
        thumbnailImgUrl:
          type: string
          nullable: true
          description: URL to the resource thumbnail image
        url:
          type: string
          nullable: true
          description: URL to access the resource (file URL or external link)
        resourceType:
          allOf:
            - $ref: '#/components/schemas/ResourceType'
          nullable: true
          description: Included when _expand contains 'resourceType'
        linkTarget:
          type: string
          nullable: true
          description: Target URL for link-type resources
    Topic:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
        itemCount:
          type: integer
          nullable: true
          description: Included when _expand contains 'itemCount'
    MediaVariantType:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
          example: Sermon Video
        contentType:
          type: string
          enum:
            - video
            - audio
        indexable:
          type: boolean
          description: Whether this variant can be indexed for search
        displayOrder:
          type: integer
          description: Order shown to users
        collectionId:
          type: integer
    MediaChapter:
      type: object
      properties:
        id:
          type: integer
        itemId:
          type: integer
        mediaAssetId:
          type: integer
        title:
          type: string
          example: Introduction
        startMs:
          type: integer
          description: Chapter start time in milliseconds
        suggested:
          type: boolean
          nullable: true
          description: Whether this chapter was AI-suggested
        accepted:
          type: boolean
          nullable: true
          description: Whether a suggested chapter has been accepted
        hidden:
          type: boolean
          description: True if chapter is suggested but not accepted
    ResourceType:
      type: object
      properties:
        id:
          type: integer
        name:
          type: string
          description: Display name for the resource category
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: Enter your API token from the Haystack dashboard

````