1. SDK
  2. Documents

​
Overview

Upload documents to provide context for your assistant via RAG. Documents can be scoped to an assistant (shared across all threads) or a thread (single conversation).

Documents are persistent — once uploaded, they stay attached until deleted. This is different from per-turn parameters like tools or system_prompt.

Supported file types: .pdf, .doc(x), .ppt(x), .xls(x), .txt, .csv, .md, .json(l), .xml, .py, .js, .ts, .jsx, .tsx, .html, .css, .cpp, .c, .h, .java, .go, .rs, .rb, .php, .sql, .png, .jpg, .jpeg, .webp, .gif, .bmp, .tiff

​
Upload to Assistant (shared context)

Documents uploaded to an assistant are available across all threads under that assistant:

  • Python

  • JavaScript

  • TypeScript

import asyncio
from backboard import BackboardClient

async def main():
    client = BackboardClient(api_key="YOUR_API_KEY")

    assistant = await client.create_assistant(
        name="Document Assistant",
        system_prompt="You are a helpful document analysis assistant"
    )

    document = await client.upload_document_to_assistant(
        assistant.assistant_id,
        "knowledge-base.pdf"
    )
    print(f"Uploaded: {document.document_id} — status: {document.status}")

if __name__ == "__main__":
    asyncio.run(main())

​
Upload to Thread (conversation-specific)

Use the thread_id from a previous send_message response:

  • Python

  • JavaScript

  • TypeScript

document = await client.upload_document_to_thread(
    thread_id,
    "meeting-notes.pdf"
)

​
Poll Document Status

Documents must reach indexed status before they’re available for RAG. Status values: pending → processing → indexed (or error).

  • Python

  • JavaScript

  • TypeScript

while True:
    status = await client.get_document_status(document.document_id)
    print(f"Status: {status.status}")
    if status.status == "indexed":
        print(f"Ready! Chunks: {status.chunk_count}, Tokens: {status.total_tokens}")
        break
    elif status.status == "error":
        print(f"Error: {status.status_message}")
        break
    await asyncio.sleep(2)

​
Query Documents (Non-Streaming)

Pass assistant_id to query that assistant’s documents. No need to create a thread first — send_message auto-creates one:

  • Python

  • JavaScript

  • TypeScript

response = await client.send_message(
    "What are the key points in the uploaded document?",
    assistant_id=assistant.assistant_id,
)
print(response.content)
print(f"Files used: {response.retrieved_files_count}")
print(f"thread_id: {response.thread_id}")

​
Query Documents (Streaming)

  • Python

  • JavaScript

  • TypeScript

async for chunk in await client.send_message(
    "Summarize the document",
    assistant_id=assistant.assistant_id,
    stream=True,
):
    if chunk.get("type") == "content_streaming":
        print(chunk.get("content", ""), end="", flush=True)
print()

​
List Documents

  • Python

  • JavaScript

  • TypeScript

docs = await client.list_assistant_documents(assistant.assistant_id)
for doc in docs:
    print(f"{doc.filename} — {doc.status}")

thread_docs = await client.list_thread_documents(thread_id)

​
Delete a Document

  • Python

  • JavaScript

  • TypeScript

result = await client.delete_document(document.document_id)