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

# Add a String

> Bulk-ingest short snippets of text directly into a corpus.

## Overview

Strings are lightweight resources for ingesting raw text without creating files. The endpoint accepts batches so you can import multiple snippets in one request. Each record is queued for ingestion, then chunked and indexed for retrieval just like uploaded files.

<Info>
  **Perfect for**: Code snippets, FAQs, short documents, configuration examples, or any text content that doesn't require file uploads.
</Info>

<Warning>
  Strings are processed asynchronously. Monitor `indexing_status` to track when content is ready for querying.
</Warning>

## Authentication

Requires valid JWT token or session authentication. You must be the owner of the target corpus.

## Request Body

<ParamField body="corpora" type="UUID" required>
  ID of the corpus that will own these text strings. Must be a corpus you created and have access to.
</ParamField>

<ParamField body="strings" type="array<object>" required>
  Array of text snippets to ingest. Each object represents one string resource.

  **Batch size recommendations:**

  * Optimal: 10-50 strings per request
  * Maximum: Check your instance configuration (typically 100-200)

  <Expandable title="String object structure">
    <ParamField body="strings[].title" type="string" required>
      Display title for the text snippet (max 100 characters). Used for identification and search context.
    </ParamField>

    <ParamField body="strings[].string" type="string" required>
      The raw text content to index. Can be any length, but very long texts (>10,000 chars) may be split into multiple chunks.

      **Best practices:**

      * Use clear, self-contained content
      * Include relevant context in each string
      * Format code blocks with proper syntax
      * Keep related information together
    </ParamField>
  </Expandable>
</ParamField>

## Example request

```bash theme={null}
curl -X POST https://{your-host}/api/data/strings/ \
  -H "Authorization: Bearer $SOAR_LABS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "corpora": "8d0f0a5d-4b5e-4c09-9db6-0e9d2aa8a9fd",
    "strings": [
      {"title": "Escalation policy", "string": "Escalate to L2 after 30 minutes."},
      {"title": "SLA definition", "string": "Critical tickets must be responded to within 10m."}
    ]
  }'
```

## Response

Returns an array of string objects (one for each submitted string):

<ResponseField name="id" type="UUID">
  Unique identifier for the string resource. Use for tracking, retrieval, or deletion.
</ResponseField>

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

<ResponseField name="updated_at" type="timestamp">
  Last update timestamp. Changes when indexing status updates.
</ResponseField>

<ResponseField name="indexed_on" type="timestamp | null">
  Timestamp when indexing completed successfully. `null` while processing.
</ResponseField>

<ResponseField name="indexing_status" type="string">
  Current processing status:

  * `PRS` - Processing (chunking and indexing in progress)
  * `IND` - Indexed (ready for queries)
  * `ERR` - Error (processing failed)
  * `PND` - Pending (queued for processing)
</ResponseField>

<ResponseField name="title" type="string">
  The display title you provided for this string.
</ResponseField>

<ResponseField name="string" type="string">
  The raw text content being indexed.
</ResponseField>

<ResponseField name="character_count" type="integer">
  Total character count of the string content. Useful for tracking corpus size.
</ResponseField>

<ResponseField name="corpora" type="UUID">
  ID of the parent corpus containing this string.
</ResponseField>

## Example Response

```json theme={null}
[
  {
    "id": "b43bbf35-9819-47a8-8aff-d4eb4b3e8219",
    "created_at": "2024-09-01T10:19:59.709807Z",
    "updated_at": "2024-09-01T10:19:59.709922Z",
    "indexed_on": null,
    "indexing_status": "PRS",
    "title": "Escalation policy",
    "string": "Escalate to L2 after 30 minutes.",
    "character_count": 35,
    "corpora": "8d0f0a5d-4b5e-4c09-9db6-0e9d2aa8a9fd"
  },
  {
    "id": "2f3c3748-173a-4ace-875d-cff12d5d71ee",
    "created_at": "2024-09-01T10:19:59.710042Z",
    "updated_at": "2024-09-01T10:19:59.710057Z",
    "indexed_on": null,
    "indexing_status": "PRS",
    "title": "SLA definition",
    "string": "Critical tickets must be responded to within 10m.",
    "character_count": 55,
    "corpora": "8d0f0a5d-4b5e-4c09-9db6-0e9d2aa8a9fd"
  }
]
```

## Important Notes

<Warning>
  **Batch Validation**: The entire request fails if any string in the batch has missing `title` or `string` fields. Validate all entries before submitting.
</Warning>

<Tip>
  Track ingestion progress via `GET /api/data/strings/?corpora={id}`. Each record transitions from `PRS` → `IND` when indexing completes.
</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"]
    CORPUS_ID = "8d0f0a5d-4b5e-4c09-9db6-0e9d2aa8a9fd"

    payload = {
        "corpora": CORPUS_ID,
        "strings": [
            {"title": "Escalation policy", "string": "Escalate to L2 after 30 minutes."},
            {"title": "SLA definition", "string": "Critical tickets must be responded to within 10m."},
        ],
    }

    response = requests.post(
        f"{BASE_URL}/api/data/strings/",
        headers={
            "Authorization": f"Bearer {TOKEN}",
            "Content-Type": "application/json",
        },
        json=payload,
        timeout=30,
    )
    response.raise_for_status()
    strings = 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 addStrings(corpusId: string) {
      const response = await fetch(`${BASE_URL}/api/data/strings/`, {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${token}`,
        },
        body: JSON.stringify({
          corpora: corpusId,
          strings: [
            { title: "Escalation policy", string: "Escalate to L2 after 30 minutes." },
            { title: "SLA definition", string: "Critical tickets must be responded to within 10m." },
          ],
        }),
      });

      if (!response.ok) {
        throw new Error(`Add strings 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 corpusId = "8d0f0a5d-4b5e-4c09-9db6-0e9d2aa8a9fd";

    var json = "{" +
        "\"corpora\":\"" + corpusId + "\"," +
        "\"strings\":[{" +
            "\"title\":\"Escalation policy\",\"string\":\"Escalate to L2 after 30 minutes.\"" +
        "},{" +
            "\"title\":\"SLA definition\",\"string\":\"Critical tickets must be responded to within 10m.\"" +
        "}]" +
    "}";

    var request = HttpRequest.newBuilder(URI.create(BASE_URL + "/api/data/strings/"))
        .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("Add strings failed: " + response.statusCode());
    }
    ```
  </Tab>
</Tabs>

## Best Practices

<AccordionGroup>
  <Accordion title="Optimize Content Structure" icon="sitemap">
    Structure strings for optimal retrieval:

    1. **Use descriptive titles** - Helps with search context and user navigation
    2. **Keep content focused** - One topic per string for better semantic matching
    3. **Include relevant keywords** - Natural language is best, avoid keyword stuffing
    4. **Add contextual information** - Background details improve answer quality
    5. **Format code properly** - Use markdown code blocks for syntax highlighting

    **Example - Good Structure:**

    ```json theme={null}
    {
      "title": "JWT Token Refresh Endpoint",
      "string": "To refresh an expired JWT token, send a POST request to /api/auth/token/refresh/ with your refresh token in the request body. The endpoint returns a new access token valid for 1 hour."
    }
    ```
  </Accordion>

  <Accordion title="Batch Import Strategies" icon="layer-group">
    Efficient batch importing techniques:

    * **Group related content** - Import FAQ sets, documentation sections together
    * **Use consistent naming** - Helps with organization and search
    * **Start small** - Test with 5-10 strings before bulk importing
    * **Monitor progress** - Poll status endpoint after each batch
    * **Handle failures gracefully** - Retry failed batches with corrections

    **Typical workflow:**

    1. Prepare 20-50 strings in a batch
    2. Submit batch via POST request
    3. Wait 5-10 seconds for initial processing
    4. Poll status endpoint until all show `IND`
    5. Proceed to next batch
  </Accordion>

  <Accordion title="Common Use Cases" icon="lightbulb">
    Ideal scenarios for string resources:

    **Developer Documentation:**

    * API endpoint descriptions
    * Code examples and snippets
    * Configuration templates
    * Error messages and solutions

    **Knowledge Base:**

    * FAQ answers
    * Policy statements
    * Product specifications
    * Troubleshooting steps

    **Training Content:**

    * Glossary definitions
    * Best practice guidelines
    * Process documentation
    * Quick reference guides
  </Accordion>

  <Accordion title="Error Prevention" icon="shield-check">
    Avoid common issues:

    **Validation Errors:**

    * Ensure every object has both `title` and `string`
    * Check title length doesn't exceed 100 characters
    * Verify corpus ID is valid UUID format

    **Processing Failures:**

    * Avoid extremely long strings (>50,000 chars)
    * Remove special control characters
    * Use UTF-8 encoding for text with unicode
    * Test special characters in small batches first

    **Performance Issues:**

    * Don't send more than 100 strings per request
    * Wait for previous batch to complete before sending next
    * Implement exponential backoff on errors
  </Accordion>
</AccordionGroup>

## Management Operations

<AccordionGroup>
  <Accordion title="List All Strings" icon="list">
    Retrieve all strings in a corpus:

    ```bash theme={null}
    curl -X GET "https://{your-host}/api/data/strings/?corpora={corpus-id}" \
      -H "Authorization: Bearer $SOAR_LABS_TOKEN"
    ```

    Supports pagination with `page` and `page_size` parameters.
  </Accordion>

  <Accordion title="Update a String" icon="pen-to-square">
    Modify an existing string's content or title:

    ```bash theme={null}
    curl -X PATCH "https://{your-host}/api/data/strings/{string-id}/" \
      -H "Authorization: Bearer $SOAR_LABS_TOKEN" \
      -H "Content-Type: application/json" \
      -d '{
        "title": "Updated Title",
        "string": "Updated content"
      }'
    ```

    Note: Updates trigger re-indexing of the content.
  </Accordion>

  <Accordion title="Delete Strings" icon="trash">
    Remove strings from the corpus:

    ```bash theme={null}
    curl -X DELETE "https://{your-host}/api/data/strings/{string-id}/" \
      -H "Authorization: Bearer $SOAR_LABS_TOKEN"
    ```

    **Warning**: Deletion is immediate and removes vector embeddings. Cannot be undone.
  </Accordion>
</AccordionGroup>


## OpenAPI

````yaml POST /api/data/strings/
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/data/strings/:
    post:
      tags:
        - Resources
      description: >-
        String creation API using Django Rest Framework.


        This viewset provides CRUD operations for String objects associated with
        a Corpora.


        ### Request Body

        ```

        {
            "corpora": "e6e8285a-2b97-48af-930b-441c502cd45e",
            "strings": [
                {
                    "title": "String 1 Title",
                    "string": "This is the first string content."
                },
                {
                    "title": "String 2 Title",
                    "string": "This is the second string content."
                },
                {
                    "title": "String 3 Title",
                    "string": "This is the third string content."
                }
            ]
        }

        ```


        ### Responses


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

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


        ### Response Body

        ```

        [
            {
                "id": "b43bbf35-9819-47a8-8aff-d4eb4b3e8219",
                "created_at": "2024-09-01T10:19:59.709807Z",
                "updated_at": "2024-09-01T10:19:59.709922Z",
                "is_indexed": false,
                "indexed_on": null,
                "title": "String 1 Title",
                "string": "This is the first string content.",
                "character_count": 33,
                "corpora": "e6e8285a-2b97-48af-930b-441c502cd45e"
            },
            {
                "id": "2f3c3748-173a-4ace-875d-cff12d5d71ee",
                "created_at": "2024-09-01T10:19:59.710042Z",
                "updated_at": "2024-09-01T10:19:59.710057Z",
                "is_indexed": false,
                "indexed_on": null,
                "title": "String 2 Title",
                "string": "This is the second string content.",
                "character_count": 34,
                "corpora": "e6e8285a-2b97-48af-930b-441c502cd45e"
            },
            {
                "id": "a86c7368-a8b4-4910-9c3c-2501f8e0d0fc",
                "created_at": "2024-09-01T10:19:59.710115Z",
                "updated_at": "2024-09-01T10:19:59.710128Z",
                "is_indexed": false,
                "indexed_on": null,
                "title": "String 3 Title",
                "string": "This is the third string content.",
                "character_count": 33,
                "corpora": "e6e8285a-2b97-48af-930b-441c502cd45e"
            }
        ]

        ```
      operationId: api_data_strings_create
      requestBody:
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/String'
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/String'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/String'
        required: true
      responses:
        '201':
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/String'
          description: ''
      security:
        - jwtHeaderAuth: []
        - jwtCookieAuth: []
        - cookieAuth: []
        - basicAuth: []
components:
  schemas:
    String:
      type: object
      properties:
        id:
          type: string
          format: uuid
          readOnly: true
        strings:
          type: array
          items:
            type: object
            additionalProperties: {}
          writeOnly: 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
        indexed_on:
          type: string
          format: date-time
          readOnly: true
          nullable: true
        indexing_status:
          allOf:
            - $ref: '#/components/schemas/IndexingStatusEnum'
          readOnly: true
        title:
          type: string
          nullable: true
          description: Title of the string
          maxLength: 100
        string:
          type: string
          description: Content of the string
        character_count:
          type: integer
          readOnly: true
          nullable: true
          description: Number of characters in the string
        corpora:
          type: string
          format: uuid
          description: Corpora to which the Maps to
      required:
        - character_count
        - corpora
        - created_at
        - id
        - indexed_on
        - indexing_status
        - string
        - strings
        - updated_at
    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

````