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

# Quickstart

> Build your first working recall in five minutes.

***

## What you'll build

```mermaid theme={"dark"}
flowchart LR
  A([1. Create Tenant]) --> B([2. Ingest Data])
  B --> C([3. Verify Processing])
  C --> D([4. Recall Context])
  D --> E([5. Pass to LLM])

  style A fill:#0f172a,stroke:#334155,stroke-width:2px,color:#f8fafc,stroke-linecap:round
  style B fill:#0f172a,stroke:#334155,stroke-width:2px,color:#f8fafc,stroke-linecap:round
  style C fill:#FF571A,stroke:#FF571A,stroke-width:2.5px,color:#f8fafc,stroke-linecap:round
  style D fill:#0f172a,stroke:#334155,stroke-width:2px,color:#f8fafc,stroke-linecap:round
  style E fill:#0f172a,stroke:#334155,stroke-width:2px,color:#f8fafc,stroke-linecap:round
```

Step 3 is async - HydraDB parses, chunks, embeds, and graphs your content in the background. Steps 1, 2, 4, and 5 run in real time.

***

## Prerequisites

* An API key from [app.hydradb.com](https://app.hydradb.com)
* A backend that can make HTTP calls, or one of the HydraDB SDKs

**Base URL:** `https://api.hydradb.com`\
**Authentication:** `Authorization: Bearer $HYDRA_DB_API_KEY` on every request (substitute the actual key value)

### Install the SDK (optional)

<CodeGroup>
  ```bash cURL theme={"dark"}
  # No install needed - use curl directly
  ```

  ```typescript TypeScript SDK theme={"dark"}
  npm install @hydradb/sdk
  ```

  ```python Python SDK theme={"dark"}
  pip install hydradb-sdk
  ```
</CodeGroup>

Initialize a client:

<CodeGroup>
  ```bash cURL theme={"dark"}
  # Set your key as an environment variable
  export HYDRA_DB_API_KEY="your_api_key"
  ```

  ```typescript TypeScript SDK theme={"dark"}
  import { HydraDBClient } from "@hydradb/sdk";

  const client = new HydraDBClient({
    token: process.env.HYDRA_DB_API_KEY
  });
  ```

  ```python Python SDK theme={"dark"}
  import os
  from hydra_db import HydraDB

  client = HydraDB(token=os.environ["HYDRA_DB_API_KEY"])
  ```
</CodeGroup>

***

<Steps>
  <Step title="Step 1 - Create a Tenant">
    A tenant is your fully isolated workspace. Everything you ingest and recall lives inside it.

    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl -X POST 'https://api.hydradb.com/tenants/create' \
        -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{"tenant_id": "my_first_tenant"}'
      ```

      ```typescript TypeScript SDK theme={"dark"}
      const response = await client.tenant.create({
        tenant_id: "my_first_tenant",
      });
      ```

      ```python Python SDK theme={"dark"}
      response = client.tenant.create(tenant_id="my_first_tenant")
      ```
    </CodeGroup>

    **Response:**

    ```json theme={"dark"}
    {
      "status": "accepted",
      "tenant_id": "my_first_tenant",
      "message": "Tenant creation started in the background. Use GET /tenants/infra/status?tenant_id=... to check progress."
    }
    ```

    <Info>
      Receiving a `"status": "accepted"` response indicates that the creation process has successfully started, but it does not imply that the tenant is fully provisioned.
    </Info>

    Tenant creation is **asynchronous**. Poll until provisioning completes before ingesting:

    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl 'https://api.hydradb.com/tenants/infra/status?tenant_id=my_first_tenant' \
        -H "Authorization: Bearer $HYDRA_DB_API_KEY"
      ```

      ```typescript TypeScript SDK theme={"dark"}
      const status = await client.tenant.getInfraStatus({
        tenant_id: "my_first_tenant"
      });
      ```

      ```python Python SDK theme={"dark"}
      status = client.tenant.get_infra_status(tenant_id="my_first_tenant")
      ```
    </CodeGroup>

    **Response:**

    ```json theme={"dark"}
    {
      "tenant_id": "my_first_tenant",
      "org_id": "free",
      "infra": {
        "scheduler_status": true,
        "graph_status": true,
        "vectorstore_status": [true, true]
      },
      "message": "Deployed infrastructure status"
    }
    ```

    Wait until `infra.scheduler_status`, `infra.graph_status`, and **both** values in `infra.vectorstore_status` are `true` before ingesting.

    <Note>
      **Typical provisioning time depends on plan:** 1–2 minutes for Free and Ship plans, 4–5 minutes for Enterprise plans (which provision physically-isolated infrastructure). Allow up to \~5 minutes in any polling loop you write.
    </Note>
  </Step>

  <Step title="Step 2 - Ingest Data">
    HydraDB has two distinct data primitives. Pick the one that matches what you're ingesting.

    ### Knowledge - documents and app sources

    [Knowledge](/essentials/knowledge) is shared, tenant-wide content that all users can recall: PDFs, DOCX files, Slack threads, Notion pages, CSVs.

    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl -X POST 'https://api.hydradb.com/ingestion/upload_knowledge' \
        -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
        -F "tenant_id=my_first_tenant" \
        -F "files=@/path/to/contract.pdf"
      ```

      ```typescript TypeScript SDK theme={"dark"}
      const result = await client.upload.knowledge({
        tenant_id: "my_first_tenant",
        files: [{ path: "/path/to/contract.pdf", filename: "contract.pdf", contentType: "application/pdf" }]
      });
      ```

      ```python Python SDK theme={"dark"}
      with open("/path/to/contract.pdf", "rb") as f:
          result = client.upload.knowledge(
              tenant_id="my_first_tenant",
              files=[("contract.pdf", f, "application/pdf")]
          )
      ```
    </CodeGroup>

    **Response:**

    ```json theme={"dark"}
    {
      "success": true,
      "results": [
        { "source_id": "ef3ea754019855e2b39e9ab5c2d26096", "filename": "contract.pdf", "status": "queued" }
      ],
      "success_count": 1,
      "failed_count": 0
    }
    ```

    ### Memories - user preferences and conversation history

    [Memories](/essentials/memories) are user-specific, dynamic context: preferences, chat history, behavioral signals, inferred traits. Each memory is scoped to a `sub_tenant_id` and is fully isolated from other users.

    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl -X POST 'https://api.hydradb.com/memories/add_memory' \
        -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "tenant_id": "my_first_tenant",
          "sub_tenant_id": "user_alex_123",
          "memories": [
            {
              "text": "User prefers detailed technical explanations and dark mode",
              "infer": true,
              "user_name": "Alex"
            }
          ]
        }'
      ```

      ```typescript TypeScript SDK theme={"dark"}
      const result = await client.upload.addMemory({
        tenant_id: "my_first_tenant",
        sub_tenant_id: "user_alex_123",
        memories: [
          {
            text: "User prefers detailed technical explanations and dark mode",
            infer: true,
            user_name: "Alex",
          },
        ],
      });
      ```

      ```python Python SDK theme={"dark"}
      result = client.upload.add_memory(
          tenant_id="my_first_tenant",
          sub_tenant_id="user_alex_123",
          memories=[
              {
                  "text": "User prefers detailed technical explanations and dark mode",
                  "infer": True,
                  "user_name": "Alex",
              }
          ],
      )
      ```
    </CodeGroup>

    **Response:**

    ```json theme={"dark"}
    {
      "success": true,
      "results": [
        { "source_id": "1d50e5cd7c196a2bbcc1a59b037b3a44", "status": "queued", "infer": true }
      ],
      "success_count": 1,
      "failed_count": 0
    }
    ```

    Both paths return a `source_id` you can use to track processing in the next step.
  </Step>

  <Step title="Step 3 - Verify Processing">
    Ingestion is asynchronous. Content passes through a pipeline before it is searchable:

    ```mermaid theme={"dark"}
    flowchart LR
      Q([Queued]) --> P([Processing])
      P --> G([Graph Creation])
      G --> C([Completed])
      P -.failure.-> E([Error])
      G -.failure.-> E

      style Q fill:#0f172a,stroke:#334155,stroke-width:2px,color:#f8fafc,stroke-linecap:round
      style P fill:#0f172a,stroke:#334155,stroke-width:2px,color:#f8fafc,stroke-linecap:round
      style G fill:#FF571A,stroke:#FF571A,stroke-width:2.5px,color:#f8fafc,stroke-linecap:round
      style C fill:#22c55e,stroke:#166534,stroke-width:2px,color:#f8fafc,stroke-linecap:round
      style E fill:#ef4444,stroke:#b91c1c,stroke-width:2px,color:#f8fafc,stroke-linecap:round
    ```

    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl -X POST \
        'https://api.hydradb.com/ingestion/verify_processing?file_ids=<source_id>&tenant_id=my_first_tenant' \
        -H "Authorization: Bearer $HYDRA_DB_API_KEY"
      ```

      ```typescript TypeScript SDK theme={"dark"}
      const status = await client.upload.verifyProcessing({
        tenant_id: "my_first_tenant",
        sub_tenant_id: "my_first_tenant",
        file_ids: ["<source_id>"],
      });
      ```

      ```python Python SDK theme={"dark"}
      status = client.upload.verify_processing(
          tenant_id="my_first_tenant",
          sub_tenant_id="my_first_tenant",
          file_ids=["<source_id>"],
      )
      ```
    </CodeGroup>

    **Response:**

    ```json theme={"dark"}
    {
      "statuses": [
        {
          "file_id": "<source_id>",
          "indexing_status": "completed",
          "success": true
        }
      ]
    }
    ```

    Poll every few seconds until `indexing_status` is `"completed"`. Most documents index in under 60 seconds; larger documents may take up to 5 minutes.
  </Step>

  <Step title="Step 4 - Recall Context">
    HydraDB exposes two recall endpoints - one per store. Use the one that matches what you ingested.

    ### For Knowledge - documents

    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl -X POST 'https://api.hydradb.com/recall/full_recall' \
        -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "tenant_id": "my_first_tenant",
          "query": "What are the pricing tiers?",
          "max_results": 5,
          "mode": "fast",
          "graph_context": true
        }'
      ```

      ```typescript TypeScript SDK theme={"dark"}
      const result = await client.recall.fullRecall({
        tenant_id: "my_first_tenant",
        query: "What are the pricing tiers?",
        max_results: 5,
        mode: "fast",
        graph_context: true
      });
      ```

      ```python Python SDK theme={"dark"}
      result = client.recall.full_recall(
          tenant_id="my_first_tenant",
          query="What are the pricing tiers?",
          max_results=5,
          mode="fast",
          graph_context=True
      )
      ```
    </CodeGroup>

    ### For Memories - user preferences

    <CodeGroup>
      ```bash cURL theme={"dark"}
      curl -X POST 'https://api.hydradb.com/recall/recall_preferences' \
        -H "Authorization: Bearer $HYDRA_DB_API_KEY" \
        -H "Content-Type: application/json" \
        -d '{
          "tenant_id": "my_first_tenant",
          "sub_tenant_id": "user_alex_123",
          "query": "answer style and tone preferences",
          "mode": "fast",
          "max_results": 3
        }'
      ```

      ```typescript TypeScript SDK theme={"dark"}
      const memories = await client.recall.recallPreferences({
        tenant_id: "my_first_tenant",
        sub_tenant_id: "user_alex_123",
        query: "answer style and tone preferences",
        mode: "fast",
        max_results: 3,
      });
      ```

      ```python Python SDK theme={"dark"}
      memories = client.recall.recall_preferences(
          tenant_id="my_first_tenant",
          sub_tenant_id="user_alex_123",
          query="answer style and tone preferences",
          mode="fast",
          max_results=3,
      )
      ```
    </CodeGroup>

    **Key flags:**

    * `mode: "thinking"` - multi-stage recall with query expansion and reranking. Better results, higher latency. Default is `"fast"`.
    * `graph_context: true` - enriches results with entity relationships from the knowledge graph. Only applies to `full_recall`.

    **Sample response** (`full_recall`):

    ```json theme={"dark"}
    {
      "chunks": [
        {
          "chunk_uuid": "a1b2c3d4-...",
          "source_id": "doc_12345",
          "chunk_content": "Tiered pricing: $29/month Starter, $79/month Pro, $199/month Enterprise...",
          "source_title": "Q4 Pricing Strategy",
          "relevancy_score": 0.92
        }
      ],
      "graph_context": {
        "query_paths": [
          {
            "triplets": [
              {
                "source": { "name": "Pricing Strategy" },
                "relation": { "canonical_predicate": "OWNED_BY" },
                "target": { "name": "Product Team" }
              }
            ]
          }
        ],
        "chunk_relations": [],
        "chunk_id_to_group_ids": {}
      }
    }
    ```

    <Note>
      **`relevancy_score`:** A metric to evaluate each chunk's relevance to the query. Ranges from `0.0` to `2.0`.
    </Note>

    `chunks` is retrieved content ranked by relevance. `graph_context` contains entity relationships extracted from your data - useful for reasoning about *how* things connect, not just *what* was said.
  </Step>

  <Step title="Step 5 - Pass it to your LLM">
    For personalized, grounded answers, call both `full_recall` and `recall_preferences` in parallel and merge the results into one prompt:

    <CodeGroup>
      ```bash cURL theme={"dark"}
      # Run both recall calls, then merge in your application layer
      ```

      ```typescript TypeScript SDK theme={"dark"}
      const [knowledge, memories] = await Promise.all([
        client.recall.fullRecall({
          tenant_id: "my_first_tenant",
          query: "What are the pricing tiers?",
          mode: "thinking",
          max_results: 5,
          graph_context: true,
        }),
        client.recall.recallPreferences({
          tenant_id: "my_first_tenant",
          sub_tenant_id: "user_alex_123",
          query: "answer style and tone preferences",
          mode: "thinking",
          max_results: 3,
        }),
      ]);

      const knowledgeCtx = buildContextString(knowledge);
      const memoryCtx = buildContextString(memories);

      const completion = await openai.chat.completions.create({
        model: "gpt-4o",
        messages: [
          {
            role: "system",
            content: "Answer using only the provided context. Match the user's preferred style.",
          },
          {
            role: "user",
            content: `User preferences:\n${memoryCtx}\n\nRelevant docs:\n${knowledgeCtx}\n\nQuestion: What are the pricing tiers?`,
          },
        ],
      });
      ```

      ```python Python SDK theme={"dark"}
      import asyncio
      from hydra_db import AsyncHydraDB

      async_client = AsyncHydraDB(token=os.environ["HYDRA_DB_API_KEY"])

      async def run():
          knowledge, memories = await asyncio.gather(
              async_client.recall.full_recall(
                  tenant_id="my_first_tenant",
                  query="What are the pricing tiers?",
                  mode="thinking",
                  max_results=5,
                  graph_context=True,
              ),
              async_client.recall.recall_preferences(
                  tenant_id="my_first_tenant",
                  sub_tenant_id="user_alex_123",
                  query="answer style and tone preferences",
                  mode="thinking",
                  max_results=3,
              ),
          )
          knowledge_ctx = build_context_string(knowledge)
          memory_ctx = build_context_string(memories)
          return knowledge_ctx, memory_ctx
      ```
    </CodeGroup>

    For the `build_context_string()` helper, see [How to Use API Results](/essentials/api-results).
  </Step>
</Steps>

***

## You're done

That's the full loop: create a tenant, ingest Knowledge and Memories, wait for processing, recall context, feed it to an LLM. Everything else in HydraDB - metadata filters, sub-tenants, graph traversal, personalization - builds on this foundation.

**Where to go next:**

* [Essentials → Memories](/essentials/memories) - how user-scoped memory works
* [Essentials → Knowledge](/essentials/knowledge) - how document ingestion works
* [Essentials → Recall](/essentials/recall) - parameters, modes, and tuning
* [API Reference](/api-reference) - full endpoint documentation
* [Cookbooks](/cookbooks) - end-to-end use case guides

Stuck? Reach out at [founders@hydradb.com](mailto:founders@hydradb.com).
