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

# Use files and vector stores

> Upload files to the MKA1 API, index them in a vector store, and run semantic search over the resulting document chunks.

Use Files to upload documents once.
Use Vector Stores to index those files for semantic search and retrieval.

This is the standard pattern for document-backed assistants, retrieval workflows, and grounded responses.

## Upload a file

Upload the file with `multipart/form-data`.
The live OpenAPI spec requires `file` and `purpose`.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm files upload \
    --file ./support-manual.pdf \
    --purpose assistants \
    -H 'X-On-Behalf-Of: <end-user-id>'
  ```

  ```ts MKA1 SDK theme={null}
  import { SDK } from '@meetkai/mka1';

  const mka1 = new SDK({ bearerAuth: 'Bearer <mka1-api-key>' });

  const file = Bun.file('./support-manual.pdf');
  const result = await mka1.llm.files.upload({
    xOnBehalfOf: '<end-user-id>', // optional — attribute the request to one of your end users
    requestBody: { file, purpose: 'assistants' },
  });
  ```

  ```ts OpenAI SDK theme={null}
  import OpenAI from 'openai';
  import fs from 'fs';

  const openai = new OpenAI({
    apiKey: '<mka1-api-key>',
    baseURL: 'https://apigw.mka1.com/api/v1/llm',
    defaultHeaders: { 'X-On-Behalf-Of': '<end-user-id>' },
  });

  const file = await openai.files.create({
    file: fs.createReadStream('./support-manual.pdf'),
    purpose: 'assistants',
  });
  ```

  ```csharp C# SDK theme={null}
  using MeetKai.MKA1;
  using MeetKai.MKA1.Types.Components;
  using MeetKai.MKA1.Types.Requests;

  var sdk = new SDK(
      bearerAuth: $"Bearer {YOUR_API_KEY}",
      serverUrl: "https://apigw.mka1.com"
  );

  var res = await sdk.Llm.Files.UploadAsync(new UploadFileRequestBody()
  {
      File = new UploadFileFile()
      {
          FileName = "support-manual.pdf",
          Content = System.IO.File.ReadAllBytes("./support-manual.pdf"),
      },
      Purpose = UploadFilePurpose.Assistants,
  });
  ```

  ```python Python SDK theme={null}
  from mka1 import SDK

  sdk = SDK(bearer_auth="Bearer YOUR_API_KEY")

  result = sdk.llm.files.upload(
      file={
          "file_name": "support-manual.pdf",
          "content": open("./support-manual.pdf", "rb"),
      },
      purpose="assistants",
  )
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/files \
    --request POST \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --form 'file=@./support-manual.pdf' \
    --form 'purpose=assistants'
  ```
</CodeGroup>

The response returns a `file` object with an ID such as `file-abc123`.

## Create a vector store

Create a vector store and attach one or more uploaded file IDs.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm vector-stores create --body '{
    "name": "Support knowledge base",
    "description": "Indexed support manuals and help center docs",
    "file_ids": ["file-abc123"],
    "expires_after": { "anchor": "last_active_at", "days": 30 }
  }'
  ```

  ```ts MKA1 SDK theme={null}
  const vectorStore = await mka1.llm.vectorStores.create({
    xOnBehalfOf: '<end-user-id>',
    createVectorStoreRequest: {
      name: 'Support knowledge base',
      description: 'Indexed support manuals and help center docs',
      fileIds: ['file-abc123'],
      expiresAfter: { anchor: 'last_active_at', days: 30 },
    },
  });
  ```

  ```ts OpenAI SDK theme={null}
  const vectorStore = await openai.vectorStores.create({
    name: 'Support knowledge base',
    description: 'Indexed support manuals and help center docs',
    file_ids: ['file-abc123'],
    expires_after: { anchor: 'last_active_at', days: 30 },
  });
  ```

  ```csharp C# SDK theme={null}
  var vs = await sdk.Llm.VectorStores.CreateAsync(new CreateVectorStoreRequest()
  {
      Name = "Support knowledge base",
      Description = "Indexed support manuals and help center docs",
  });
  ```

  ```python Python SDK theme={null}
  vector_store = sdk.llm.vector_stores.create(
      name="Support knowledge base",
      description="Indexed support manuals and help center docs",
  )
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/vector_stores \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --data '{
      "name": "Support knowledge base",
      "description": "Indexed support manuals and help center docs",
      "file_ids": [
        "file-abc123"
      ],
      "expires_after": {
        "anchor": "last_active_at",
        "days": 30
      }
    }'
  ```
</CodeGroup>

This response returns a vector store ID such as `vs_abc123`.

## Add more files later

You can add more files to an existing vector store without recreating it.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm vector-stores create-file \
    --vector-store-id vs_abc123 \
    --file-id file-def456 \
    --attributes '{"category":"manual","version":"2.0"}'
  ```

  ```ts MKA1 SDK theme={null}
  const vsFile = await mka1.llm.vectorStores.createFile({
    vectorStoreId: 'vs_abc123',
    xOnBehalfOf: '<end-user-id>',
    createVectorStoreFileRequest: {
      fileId: 'file-def456',
      attributes: { category: 'manual', version: '2.0' },
    },
  });
  ```

  ```ts OpenAI SDK theme={null}
  const vsFile = await openai.vectorStores.files.create('vs_abc123', {
    file_id: 'file-def456',
  });
  ```

  ```csharp C# SDK theme={null}
  // Adding files to an existing vector store is done via the
  // VectorStores.CreateFile or VectorStores.Files API methods.
  // Refer to the API reference for the full method signature.
  ```

  ```python Python SDK theme={null}
  vs_file = sdk.llm.vector_stores.create_file(
      vector_store_id="vs_abc123",
      file_id="file-def456",
  )
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/vector_stores/vs_abc123/files \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --data '{
      "file_id": "file-def456",
      "attributes": {
        "category": "manual",
        "version": "2.0"
      }
    }'
  ```
</CodeGroup>

The vector store file can return `status: "in_progress"` while indexing runs.
Check the Files and Vector Stores endpoints in the API Reference if you need to poll for status.

## List files with pagination

File listings are sorted by `created_at` (newest first by default) and return up to `limit` items per page.
When `has_more` is `true`, pass the last item's `id` as `after` to fetch the next page.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm vector-stores list-files \
    --vector-store-id vs_abc123 \
    --limit 5 \
    --after file-def456
  ```

  ```ts MKA1 SDK theme={null}
  let after: string | undefined;
  do {
    const page = await mka1.llm.vectorStores.listFiles({
      vectorStoreId: 'vs_abc123',
      limit: 5,
      after,
      xOnBehalfOf: '<end-user-id>',
    });
    for (const vsFile of page.data) {
      console.log(vsFile.id);
    }
    after = page.hasMore ? page.lastId : undefined;
  } while (after);
  ```

  ```ts OpenAI SDK theme={null}
  // The OpenAI SDK auto-paginates: iterate and it follows the cursor for you.
  for await (const vsFile of openai.vectorStores.files.list('vs_abc123', {
    limit: 5,
  })) {
    console.log(vsFile.id);
  }
  ```

  ```csharp C# SDK theme={null}
  // Listing is available via the VectorStores.ListFiles method; pass the last
  // item's id as `after` while `has_more` is true.
  // Refer to the API reference for the full method signature.
  ```

  ```python Python SDK theme={null}
  after = None
  while True:
      page = sdk.llm.vector_stores.list_files(
          vector_store_id="vs_abc123",
          limit=5,
          after=after,
      )
      for vs_file in page.data:
          print(vs_file.id)
      if not page.has_more:
          break
      after = page.last_id
  ```

  ```bash bash theme={null}
  curl "https://apigw.mka1.com/api/v1/llm/vector_stores/vs_abc123/files?limit=5&after=file-def456" \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>'
  ```
</CodeGroup>

To page backwards, pass an item's `id` as `before` instead: the response is the page immediately preceding that item in the display order.
Files attached in the same batch can share a creation timestamp; the cursor accounts for this, so a full walk returns every file exactly once.

If a cursor's file no longer exists — for example, it was removed from the vector store while you were paging — the API returns `400 Invalid pagination cursor`. Restart the walk from the first page.

## Search the vector store

Use semantic search to retrieve the most relevant chunks for a user question.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm vector-stores search \
    --vector-store-id vs_abc123 \
    --body '{
      "query": "How do I reset my password?",
      "max_num_results": 5
    }'
  ```

  ```ts MKA1 SDK theme={null}
  const results = await mka1.llm.vectorStores.search({
    vectorStoreId: 'vs_abc123',
    xOnBehalfOf: '<end-user-id>',
    searchVectorStoreRequest: {
      query: 'How do I reset my password?',
      maxNumResults: 5,
    },
  });
  ```

  ```ts OpenAI SDK theme={null}
  const results = await openai.vectorStores.search('vs_abc123', {
    query: 'How do I reset my password?',
    max_num_results: 5,
  });
  ```

  ```csharp C# SDK theme={null}
  // Search is available via the VectorStores.Search method.
  // Refer to the API reference for the full method signature.
  ```

  ```python Python SDK theme={null}
  results = sdk.llm.vector_stores.search(
      vector_store_id="vs_abc123",
      query="How do I reset my password?",
  )
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/vector_stores/vs_abc123/search \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --data '{
      "query": "How do I reset my password?",
      "max_num_results": 5
    }'
  ```
</CodeGroup>

The response returns ranked matches with `file_id`, `filename`, score data, chunk content, and the file's current `attributes`.

## Filter search by file attributes

Attributes are file-level key-value metadata — string, number, or boolean values — set when you attach a file (see [Add more files later](#add-more-files-later)).
You can change them after ingest with the update-file endpoint (`POST /vector_stores/{vector_store_id}/files/{file_id}`); search always evaluates the current values.

Pass `filters` in the search request to restrict results to files whose attributes match.
A filter is either a comparison — `eq`, `ne`, `gt`, `gte`, `lt`, `lte`, `in`, `nin` — or an `and`/`or` compound of nested filters.

<CodeGroup>
  ```bash CLI theme={null}
  mka1 llm vector-stores search \
    --vector-store-id vs_abc123 \
    --body '{
      "query": "How do I reset my password?",
      "max_num_results": 5,
      "filters": {
        "type": "and",
        "filters": [
          { "type": "eq", "key": "category", "value": "manual" },
          { "type": "ne", "key": "version", "value": "1.0" }
        ]
      }
    }'
  ```

  ```ts MKA1 SDK theme={null}
  const results = await mka1.llm.vectorStores.search({
    vectorStoreId: 'vs_abc123',
    xOnBehalfOf: '<end-user-id>',
    searchVectorStoreRequest: {
      query: 'How do I reset my password?',
      maxNumResults: 5,
      filters: {
        type: 'and',
        filters: [
          { type: 'eq', key: 'category', value: 'manual' },
          { type: 'ne', key: 'version', value: '1.0' },
        ],
      },
    },
  });
  ```

  ```ts OpenAI SDK theme={null}
  const results = await openai.vectorStores.search('vs_abc123', {
    query: 'How do I reset my password?',
    max_num_results: 5,
    filters: {
      type: 'and',
      filters: [
        { type: 'eq', key: 'category', value: 'manual' },
        { type: 'ne', key: 'version', value: '1.0' },
      ],
    },
  });
  ```

  ```csharp C# SDK theme={null}
  // Filtered search is available via the VectorStores.Search method's Filters
  // parameter (ComparisonFilter / CompoundFilter).
  // Refer to the API reference for the full method signature.
  ```

  ```python Python SDK theme={null}
  results = sdk.llm.vector_stores.search(
      vector_store_id="vs_abc123",
      query="How do I reset my password?",
      filters={
          "type": "and",
          "filters": [
              {"type": "eq", "key": "category", "value": "manual"},
              {"type": "ne", "key": "version", "value": "1.0"},
          ],
      },
  )
  ```

  ```bash bash theme={null}
  curl https://apigw.mka1.com/api/v1/llm/vector_stores/vs_abc123/search \
    --request POST \
    --header 'Content-Type: application/json' \
    --header 'Authorization: Bearer <mka1-api-key>' \
    --header 'X-On-Behalf-Of: <end-user-id>' \
    --data '{
      "query": "How do I reset my password?",
      "max_num_results": 5,
      "filters": {
        "type": "and",
        "filters": [
          { "type": "eq", "key": "category", "value": "manual" },
          { "type": "ne", "key": "version", "value": "1.0" }
        ]
      }
    }'
  ```
</CodeGroup>

Filter evaluation follows these rules:

* A file that does not have the filter's `key` never matches — including for `ne` and `nin`. A filter only opts a file in on evidence, never by absence.
* `eq` and `ne` are strict equality with no type coercion: the string `"2"` does not equal the number `2`.
* `gt`, `gte`, `lt`, and `lte` compare numbers only; a non-numeric attribute or filter value fails the comparison.
* `in` and `nin` take an array `value` and test whether the file's attribute is (or is not) one of its elements.
* `and` and `or` compounds nest to any depth.
* On graph stores ([GraphRAG](/docs/graphrag)), filtering is applied after retrieval, so a filtered search can return fewer than `max_num_results` matches.

## Typical workflow

Use this sequence for most retrieval setups:

1. Upload the source file.
2. Create a vector store with `file_ids`, or attach the file later.
3. Wait for file processing to complete.
4. Search the vector store when you need relevant context.

You can then feed the returned text into your own application logic or a Responses request.
