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

# Create Corpus

> Provision a new knowledge base that resources can be ingested into.

## Overview

Create a corpus before uploading any resources. Every corpus belongs to the authenticated user and encapsulates indexing configuration (vector index type, publication flag, etc.). Back-end logic normalizes the name into lowercase snake\_case and enforces uniqueness per user.

<Info>
  **Prerequisite**: You must be authenticated with a valid JWT token or session cookie.
</Info>

## Request Body

<ParamField body="corpora_name" type="string" required>
  Human-friendly name for your corpus. The system automatically converts it to lowercase with underscores (e.g., "Support Playbooks" becomes "support\_playbooks"). Must be unique for your user account.
</ParamField>

<ParamField body="description" type="string">
  Optional context about what content lives in this corpus. Helps you and your team understand the corpus purpose.
</ParamField>

<ParamField body="is_published" type="boolean" default="false">
  Controls whether the corpus is discoverable via public listings. Set to `true` for shared knowledge bases.
</ParamField>

<ParamField body="index_type" type="string" default="VSI">
  Indexing strategy for the corpus. Available options:

  * `VSI` - Vector Store Index (recommended for semantic search)
  * `SMI` - Summary Index
  * `DSI` - Document Summary Index
</ParamField>

<ParamField body="indexing_status" type="string">
  System-managed field that tracks indexing progress. Leave empty - Soar Labs automatically updates this as ingestion jobs complete.

  **Status values:**

  * `PND` - Pending (newly created)
  * `PRS` - Processing (ingestion in progress)
  * `IND` - Indexed (ready for queries)
  * `ERR` - Error (ingestion failed)
</ParamField>

## Example request

```bash theme={null}
curl -X POST https://{your-host}/api/corpora/ \
  -H "Authorization: Bearer $SOAR_LABS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "corpora_name": "Support Playbooks",
    "description": "Runbooks feeding LlamaIndex",
    "is_published": false,
    "index_type": "VSI"
  }'
```

## Response

<ResponseField name="id" type="UUID">
  Unique identifier for the corpus. Use this ID in all subsequent operations (uploading resources, querying, etc.).
</ResponseField>

<ResponseField name="created_at" type="timestamp">
  ISO 8601 timestamp when the corpus was created.
</ResponseField>

<ResponseField name="updated_at" type="timestamp">
  ISO 8601 timestamp of the last update to corpus metadata.
</ResponseField>

<ResponseField name="corpora_name" type="string">
  Normalized corpus name in lowercase snake\_case format.
</ResponseField>

<ResponseField name="description" type="string">
  User-provided description of the corpus content and purpose.
</ResponseField>

<ResponseField name="size_on_disk" type="float">
  Total storage size in bytes. Initially `0.0` for new corpora, updates as resources are ingested.
</ResponseField>

<ResponseField name="index_location" type="string | null">
  Storage location of the vector index (e.g., `"qdrant_free_collection"`). `null` until first resource is indexed.
</ResponseField>

<ResponseField name="is_published" type="boolean">
  Whether the corpus is publicly discoverable.
</ResponseField>

<ResponseField name="index_type" type="string">
  The indexing strategy: `VSI` (Vector Store), `SMI` (Summary), or `DSI` (Document Summary).
</ResponseField>

<ResponseField name="indexing_status" type="string">
  Current indexing status: `PND` (Pending), `PRS` (Processing), `IND` (Indexed), or `ERR` (Error).
</ResponseField>

<ResponseField name="creator" type="UUID">
  User ID of the corpus creator. Read-only field for ownership tracking.
</ResponseField>

## Example Response

```json theme={null}
{
  "id": "8d0f0a5d-4b5e-4c09-9db6-0e9d2aa8a9fd",
  "created_at": "2024-09-01T10:05:03.291Z",
  "updated_at": "2024-09-01T10:05:03.291Z",
  "corpora_name": "support_playbooks",
  "description": "Runbooks feeding LlamaIndex",
  "size_on_disk": 0.0,
  "index_location": null,
  "is_published": false,
  "index_type": "VSI",
  "indexing_status": "PND",
  "creator": "eb81c1d5-78fe-4f35-b58e-0ff6a3ad5d12"
}
```

## Best Practices

<AccordionGroup>
  <Accordion title="Check Name Availability" icon="check-circle">
    Use `GET /api/check_corpora_name/?corpora_name=your_name` to validate name availability before creating a corpus. This prevents 400 errors from duplicate names.

    ```bash theme={null}
    curl -X GET "https://{your-host}/api/check_corpora_name/?corpora_name=support_playbooks" \
      -H "Authorization: Bearer $SOAR_LABS_TOKEN"
    ```
  </Accordion>

  <Accordion title="Store the Corpus ID" icon="bookmark">
    Save the returned `id` field immediately - you'll need it for:

    * Uploading resources (`POST /api/data/files/`, `/urls/`, `/strings/`)
    * Executing queries (`POST /api/query/`)
    * Retrieving corpus details (`GET /api/corpora/{id}/`)
  </Accordion>

  <Accordion title="Monitor Indexing Status" icon="clock">
    Track the `indexing_status` field as resources are added:

    * `PND` → `PRS` → `IND`: Normal progression
    * `ERR`: Check resource ingestion logs for failures

    Poll `GET /api/corpora/{id}/` to monitor status changes.
  </Accordion>

  <Accordion title="Understanding Read-Only Fields" icon="info-circle">
    The following fields are managed by SOAR and cannot be set directly:

    * `size_on_disk` - Updated as resources are indexed
    * `index_location` - Assigned when first resource is processed
    * `creator` - Automatically set to your user ID
    * `id`, `created_at`, `updated_at` - System-generated metadata
  </Accordion>
</AccordionGroup>

<Tip>
  Choose `VSI` (Vector Store Index) for most use cases. It provides the best semantic search capabilities and works well with the advanced RAG retrieval pipeline.
</Tip>

## Client examples

<Tabs>
  <Tab title="Python">
    ```python theme={null}
    import os
    import requests

    BASE_URL = "https://your-soar-instance.com"
    TOKEN = os.environ["SOAR_LABS_TOKEN"]

    payload = {
        "corpora_name": "support_playbooks",
        "description": "Runbooks feeding LlamaIndex",
    }

    response = requests.post(
        f"{BASE_URL}/api/corpora/",
        headers={
            "Authorization": f"Bearer {TOKEN}",
            "Content-Type": "application/json",
        },
        json=payload,
        timeout=30,
    )
    response.raise_for_status()
    corpus = response.json()
    ```
  </Tab>

  <Tab title="TypeScript / JavaScript">
    ```ts theme={null}
    const BASE_URL = "https://your-soar-instance.com";
    const token = process.env.SOAR_LABS_TOKEN!;

    async function createCorpus() {
      const response = await fetch(`${BASE_URL}/api/corpora/`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${token}`,
        },
        body: JSON.stringify({
          corpora_name: "support_playbooks",
          description: "Runbooks feeding LlamaIndex",
        }),
      });

      if (!response.ok) {
        throw new Error(`Create corpus failed: ${response.status}`);
      }

      return response.json();
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    import java.net.URI;
    import java.net.http.HttpClient;
    import java.net.http.HttpRequest;
    import java.net.http.HttpResponse;

    var BASE_URL = "https://your-soar-instance.com";
    var token = System.getenv("SOAR_LABS_TOKEN");

    var json = "{" +
        "\"corpora_name\":\"support_playbooks\"," +
        "\"description\":\"Runbooks feeding LlamaIndex\"" +
    "}";

    var request = HttpRequest.newBuilder(URI.create(BASE_URL + "/api/corpora/"))
        .header("Authorization", "Bearer " + token)
        .header("Content-Type", "application/json")
        .POST(HttpRequest.BodyPublishers.ofString(json))
        .build();

    var response = HttpClient.newHttpClient().send(request, HttpResponse.BodyHandlers.ofString());

    if (response.statusCode() >= 400) {
        throw new RuntimeException("Create corpus failed: " + response.statusCode());
    }

    var body = response.body();
    ```
  </Tab>
</Tabs>


## OpenAPI

````yaml POST /api/corpora/
openapi: 3.0.3
info:
  title: Soar Labs API - Insider Dev preview
  version: 0.1.0
  description: <b>Soar Labs Advanced RAG platform</b>
servers: []
security: []
paths:
  /api/corpora/:
    post:
      tags:
        - Corpora
      description: >-
        Corpora creation API using Django Rest Framework.


        This viewset provides CRUD operations for Corpora objects.


        ### Responses


        - **201 Created**: Returned on successful creation of a Corpora.

        - **400 Bad Request**: Returned if the request data is invalid.

        - **401 Unauthorized**: Returned if the user is not authenticated.

        - **403 Forbidden**: Returned if the user is not authorized to perform
        the operation.

        - **404 Not Found**: Returned if the requested Corpora does not exist.


        ### Permissions

        - `IsAuthenticated`: Users must be authenticated to access this
        endpoint.
      operationId: api_corpora_create
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/Corpora'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/Corpora'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/Corpora'
        required: true
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Corpora'
          description: ''
      security:
        - jwtHeaderAuth: []
        - jwtCookieAuth: []
        - cookieAuth: []
        - basicAuth: []
components:
  schemas:
    Corpora:
      type: object
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        created_at:
          type: string
          format: date-time
          readOnly: true
          description: The date and time the organization was created
        updated_at:
          type: string
          format: date-time
          readOnly: true
          description: Last updated time
        corpora_name:
          type: string
          description: Name of the corpora
          maxLength: 100
        description:
          type: string
          nullable: true
          description: Description of the corpora
        size_on_disk:
          type: number
          format: double
          readOnly: true
          title: Size
          description: Size of the corpora on disk (in bytes)
        index_location:
          type: string
          readOnly: true
          nullable: true
          title: Location of Index
          description: Location of the index on Remote Storage
        is_published:
          type: boolean
          title: Publishing Status
          description: Is the corpora Visible to all users?
        index_type:
          allOf:
            - $ref: '#/components/schemas/IndexTypeEnum'
          description: |-
            Type of index to be used for the corpora

            * `VSI` - VectorStoreIndex
            * `SMI` - SummaryIndex
            * `DSI` - DocumentSummaryIndex
        indexing_status:
          allOf:
            - $ref: '#/components/schemas/IndexingStatusEnum'
          title: Index Processing Status
          description: |-
            Status of the corpora processing

            * `PND` - Pending
            * `IQE` - In Queue
            * `PRS` - Processing
            * `DEX` - Data Extracted Successfully
            * `DER` - Data Extraction Error
            * `IND` - Indexed
            * `CMP` - Completed
            * `ERR` - Error
        creator:
          type: string
          format: uuid
          readOnly: true
      required:
        - corpora_name
        - created_at
        - creator
        - id
        - index_location
        - size_on_disk
        - updated_at
    IndexTypeEnum:
      enum:
        - VSI
        - SMI
        - DSI
      type: string
      description: |-
        * `VSI` - VectorStoreIndex
        * `SMI` - SummaryIndex
        * `DSI` - DocumentSummaryIndex
    IndexingStatusEnum:
      enum:
        - PND
        - IQE
        - PRS
        - DEX
        - DER
        - IND
        - CMP
        - ERR
      type: string
      description: |-
        * `PND` - Pending
        * `IQE` - In Queue
        * `PRS` - Processing
        * `DEX` - Data Extracted Successfully
        * `DER` - Data Extraction Error
        * `IND` - Indexed
        * `CMP` - Completed
        * `ERR` - Error
  securitySchemes:
    jwtHeaderAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
    jwtCookieAuth:
      type: apiKey
      in: cookie
      name: soar-app-auth
    cookieAuth:
      type: apiKey
      in: cookie
      name: sessionid
    basicAuth:
      type: http
      scheme: basic

````