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

# Deploy REST API Server

> Deploy Cognee as a REST API server using Docker or Python

Deploy Cognee as a REST API server to expose its functionality via HTTP endpoints.

## Setup

```bash theme={null}
# Clone repository
git clone https://github.com/topoteretes/cognee.git
cd cognee

# Configure environment
cp .env.template .env
```

<Info>
  Edit `.env` with your preferred configuration. See [Setup Configuration](/setup-configuration/overview) guides for all available options.
</Info>

## Deployment Methods

<Tabs>
  <Tab title="Docker">
    ### Start Server

    ```bash theme={null}
    # Start API server
    docker compose up --build cognee

    # Check status
    docker compose ps
    ```
  </Tab>

  <Tab title="Python (Local)">
    ### Setup

    ```bash theme={null}
    # Create virtual environment
    uv venv && source .venv/bin/activate

    # Install with all extras
    uv sync --all-extras
    ```

    ### Start Server

    ```bash theme={null}
    # Run API server
    uvicorn cognee.api.client:app --host 0.0.0.0 --port 8000
    ```

    Alternatively, launch the server through the module entry point, which accepts a `--agent-mode` flag:

    ```bash theme={null}
    # Standard mode (defaults to port 8000)
    python cognee/api/client.py

    # Agent mode (defaults to port 8011)
    python cognee/api/client.py --agent-mode
    ```

    Passing `--agent-mode` sets `COGNEE_AGENT_MODE=true` for the process and overrides the environment variable if it is also set. Agent mode is intended for ephemeral deployments where an orchestrator spins up Cognee for one or more agents; the server tracks agents that call `POST /api/v1/agents/register` and shuts itself down once the active count drops back to zero (driven by `POST /api/v1/agents/unregister`). The auto-shutdown watchdog only starts after the first connection registers, so a fresh agent-mode server stays up while it waits. Host and port can still be overridden with `HTTP_API_HOST` and `HTTP_API_PORT`.
  </Tab>
</Tabs>

## Access API

* **API:** [http://localhost:8000](http://localhost:8000)
* **Documentation:** [http://localhost:8000/docs](http://localhost:8000/docs)

## Agent Mode

Cognee can run in **agent mode**, which tracks active agent connections and shuts the
server down once they all disconnect. This is intended for ephemeral deployments where
an external orchestrator launches a Cognee server for one or more agents and tears it
down when they finish.

Enable agent mode in either of two ways:

```bash theme={null}
# CLI flag (when running the API server directly)
python -m cognee.api.client --agent-mode

# Environment variable
COGNEE_AGENT_MODE=true uvicorn cognee.api.client:app --host 0.0.0.0
```

When agent mode is enabled:

* The **default port becomes `8011`** (instead of `8000`). The CLI flag overrides the
  `COGNEE_AGENT_MODE` env var. `HTTP_API_PORT` still wins if you set it explicitly.
* A background watchdog starts **after the first** `POST /api/v1/agents/register` call
  and checks the active connection count every **60 seconds**. When the count drops to
  zero, the watchdog sends `SIGTERM` to the server process.
* The server stays alive indefinitely while waiting for the first registration —
  the watchdog does not arm until then.

Agents call `POST /api/v1/agents/register` on connect and `POST /api/v1/agents/unregister`
on disconnect; see the **Agent Management** accordion below for the full surface.

## Authentication

If `REQUIRE_AUTHENTICATION=true` in your `.env` file:

1. **Register:** `POST /api/v1/auth/register`
2. **Login:** `POST /api/v1/auth/login`
3. **Use token:** Include `Authorization: Bearer <token>` header or use cookies

## Python SDK Client

After deploying the server, connect the Python SDK to your running instance using `cognee.serve()`:

```python theme={null}
import cognee
import asyncio

async def main():
    client = await cognee.serve(url="http://localhost:8000")
    # Pass api_key="..." only when REQUIRE_AUTHENTICATION=true

    # Ingest data and build the knowledge graph in one step
    await client.remember("Cognee turns documents into AI memory.", dataset_name="docs")

    # Query the knowledge graph
    results = await client.recall("What does Cognee do?")
    for result in results:
        print(result)

    await cognee.disconnect()

asyncio.run(main())
```

You can also configure the connection via environment variables instead of passing arguments to `serve()`:

```bash theme={null}
export COGNEE_SERVICE_URL="http://localhost:8000"
export COGNEE_API_KEY="<your-key>"  # required only when REQUIRE_AUTHENTICATION=true
```

```python theme={null}
client = await cognee.serve()  # reads COGNEE_SERVICE_URL and COGNEE_API_KEY
```

The `CloudClient` returned by `serve()` exposes four methods that map to the server's V2 endpoints: `remember()` (ingest + cognify), `recall()` (search), `improve()` (enrich graph), and `forget()` (delete). Call `await cognee.disconnect()` to revert to local mode.

### Uploading skills

`client.remember(..., content_type="skills")` ingests local `SKILL.md` files as Skill nodes. Pass either a single `SKILL.md` file path or a directory; directories are searched recursively for `SKILL.md` files. The client reads the local file contents and uploads their bytes (preserving the relative folder layout), so the path is resolved on the **caller's** machine rather than on the server:

```python theme={null}
client = await cognee.serve(url="http://localhost:8000")

# A directory tree — every SKILL.md under ./skills is uploaded
await client.remember("./skills", dataset_name="agent_skills", content_type="skills")

# Or a single SKILL.md file
await client.remember("./skills/demo/SKILL.md", dataset_name="agent_skills", content_type="skills")
```

The client raises `FileNotFoundError` when the path does not exist and `ValueError` when a directory contains no `SKILL.md` files.

<Note>
  When a skill push reaches the server without any file named `SKILL.md` — for example a direct `POST /api/v1/remember` upload with `content_type=skills` whose uploaded files use other names — the server now ingests each uploaded file as an individual skill instead of skipping the push. Pushes that already contain `SKILL.md` files are ingested as before, preserving their folder layout.
</Note>

## HTTP API Examples

<AccordionGroup>
  <Accordion title="Authentication">
    **Register a user:**

    ```bash theme={null}
    curl -X POST "http://localhost:8000/api/v1/auth/register" \
      -H "Content-Type: application/json" \
      -d '{"email": "user1@example.com", "password": "strong_password"}'
    ```

    **Login and get token:**

    ```bash theme={null}
    TOKEN="$(curl -s -X POST http://localhost:8000/api/v1/auth/login \
      -H 'Content-Type: application/x-www-form-urlencoded' \
      -d 'username=user1@example.com&password=strong_password' | jq -r .access_token)"
    ```
  </Accordion>

  <Accordion title="Dataset Management">
    **Create a dataset:**

    ```bash theme={null}
    curl -X POST http://localhost:8000/api/v1/datasets \
      -H "Content-Type: application/json" \
      -H "Authorization: Bearer $TOKEN" \
      -d '{"name": "project_docs"}'
    ```

    **List datasets:**

    ```bash theme={null}
    curl -H "Authorization: Bearer $TOKEN" http://localhost:8000/api/v1/datasets
    ```
  </Accordion>

  <Accordion title="Data Operations">
    <Tabs>
      <Tab title="Cognee v1.0">
        **Remember data and build memory in one call:**

        ```bash theme={null}
        curl -X POST http://localhost:8000/api/v1/remember \
          -H "Authorization: Bearer $TOKEN" \
          -F "data=@/absolute/path/to/file.pdf" \
          -F "datasetName=project_docs" \
          -F "chunk_size=1024" \
          -F "chunks_per_batch=20" \
          -F "run_in_background=false"
        ```

        **Recall from a dataset with explicit retrieval settings:**

        ```bash theme={null}
        curl -X POST http://localhost:8000/api/v1/recall \
          -H "Content-Type: application/json" \
          -H "Authorization: Bearer $TOKEN" \
          -d '{"query": "What are the main topics?", "datasets": ["project_docs"], "search_type": "GRAPH_COMPLETION", "top_k": 10}'
        ```

        **Improve an existing dataset in the background:**

        ```bash theme={null}
        curl -X POST http://localhost:8000/api/v1/improve \
          -H "Content-Type: application/json" \
          -H "Authorization: Bearer $TOKEN" \
          -d '{"dataset_name": "project_docs", "run_in_background": true}'
        ```

        **Forget only derived memory and keep the uploaded files:**

        ```bash theme={null}
        curl -X POST http://localhost:8000/api/v1/forget \
          -H "Content-Type: application/json" \
          -H "Authorization: Bearer $TOKEN" \
          -d '{"dataset": "project_docs", "memory_only": true}'
        ```
      </Tab>

      <Tab title="Legacy Operations">
        Use these lower-level endpoints when you want to keep ingestion, graph building, and retrieval as separate steps.

        **Add data (upload file):**

        ```bash theme={null}
        curl -X POST http://localhost:8000/api/v1/add \
          -H "Authorization: Bearer $TOKEN" \
          -F "data=@/absolute/path/to/file.pdf" \
          -F "datasetName=project_docs"
        ```

        **Build the knowledge graph with a custom chunk size:**

        ```bash theme={null}
        curl -X POST http://localhost:8000/api/v1/cognify \
          -H "Content-Type: application/json" \
          -H "Authorization: Bearer $TOKEN" \
          -d '{"datasets": ["project_docs"], "chunk_size": 1024}'
        ```

        **Search data:**

        ```bash theme={null}
        curl -X POST http://localhost:8000/api/v1/search \
          -H "Content-Type: application/json" \
          -H "Authorization: Bearer $TOKEN" \
          -d '{"query": "What are the main topics?", "datasets": ["project_docs"], "top_k": 10}'
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="Uploading files, raw text, and remote servers">
    Both `POST /api/v1/remember` and `POST /api/v1/add` expect **`multipart/form-data`**, where `data` is one or more **file uploads** — not a JSON body or a plain form string. Sending text directly (for example `-F "data=some text"` or a JSON `{"data": "..."}` body) fails validation with:

    ```
    Value error, Expected UploadFile, received: <class 'str'>
    ```

    Attach a file with curl's `@` prefix instead:

    ```bash theme={null}
    curl -X POST http://localhost:8000/api/v1/remember \
      -H "Authorization: Bearer $TOKEN" \
      -F "data=@/absolute/path/to/file.pdf" \
      -F "datasetName=project_docs"
    ```

    To ingest raw text, write it to a file first and upload that file:

    ```bash theme={null}
    echo "Cognee turns documents into AI memory." > note.txt

    curl -X POST http://localhost:8000/api/v1/remember \
      -H "Authorization: Bearer $TOKEN" \
      -F "data=@note.txt" \
      -F "datasetName=project_docs"
    ```

    You can attach multiple files by repeating `-F "data=@..."`. If you prefer to send raw strings as JSON, use the [Python SDK](/python-api/remember) (`await client.remember("some text", ...)`) or the [`POST /api/v1/skills`](/api-reference/introduction) JSON endpoint for skill markdown — the multipart endpoints always require file uploads.

    **Targeting a remote (non-localhost) server:** replace `http://localhost:8000` with your server's address, e.g. `http://<host-or-ip>:8000` on a private network or `https://cognee.example.com` behind a reverse proxy. Bind the server to a reachable interface with `--host 0.0.0.0` (see the [Python (Local)](#deployment-methods) tab), and keep [authentication](#authentication) enabled whenever the server is not on a trusted, private network.
  </Accordion>

  <Accordion title="Activity and Observability">
    The `/api/v1/activity` router exposes endpoints for pipeline run history, trace data, tenant or agent monitoring, and dataset export. All endpoints require authentication.

    | Endpoint                                   | Description                                                                                                                          |
    | ------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------ |
    | `GET /api/v1/activity/pipeline-runs`       | Last 50 pipeline runs with dataset name and owner. Accepts optional `?dataset_id=<uuid>` to filter by dataset.                       |
    | `GET /api/v1/activity/spans`               | In-memory OTEL span buffer (last 50 traces). Requires `COGNEE_TRACING_ENABLED=true`. Returns an empty list when tracing is disabled. |
    | `GET /api/v1/activity/users`               | All active users in the current tenant.                                                                                              |
    | `GET /api/v1/activity/agents`              | Registered agents with `status` (`LIVE` / `INACTIVE`), API key count, and recent activity flag.                                      |
    | `GET /api/v1/activity/export/{dataset_id}` | Downloads the dataset's knowledge graph as a Markdown export.                                                                        |

    <Tabs>
      <Tab title="Pipeline Runs">
        ```bash theme={null}
        curl -H "Authorization: Bearer $TOKEN" \
          "http://localhost:8000/api/v1/activity/pipeline-runs"
        ```
      </Tab>

      <Tab title="Trace Buffer">
        ```bash theme={null}
        curl -H "Authorization: Bearer $TOKEN" \
          "http://localhost:8000/api/v1/activity/spans"
        ```
      </Tab>

      <Tab title="Dataset Export">
        ```bash theme={null}
        curl -L -H "Authorization: Bearer $TOKEN" \
          "http://localhost:8000/api/v1/activity/export/<dataset_id>"

          The `/api/v1/activity/spans` response mirrors the same in-memory trace buffer used by the Python OpenTelemetry helpers such as `get_all_traces()`.
        ```
      </Tab>
    </Tabs>
  </Accordion>

  <Accordion title="LLM Utility Endpoints">
    When running Cognee as a server, two `/api/v1/llm` endpoints can help you bootstrap a custom extraction prompt from sample text:

    * `POST /api/v1/llm/infer-schema` — analyze sample text and return a graph schema
    * `POST /api/v1/llm/custom-prompt` — generate a custom extraction prompt from that schema

    Typical flow: infer a schema from sample text, generate a prompt, then pass that prompt to `POST /api/v1/cognify`.

    <Tabs>
      <Tab title="Infer Schema">
        ```bash theme={null}
        curl -X POST "http://localhost:8000/api/v1/llm/infer-schema" \
          -H "Authorization: Bearer $TOKEN" \
          -H "Content-Type: application/json" \
          -d '{"text": "Alice moved to Paris. Bob founded Acme Corp in New York."}'
        ```
      </Tab>

      <Tab title="Generate Prompt">
        ```bash theme={null}
        curl -X POST "http://localhost:8000/api/v1/llm/custom-prompt" \
          -H "Authorization: Bearer $TOKEN" \
          -H "Content-Type: application/json" \
          -d '{"graphModel": {"title": "PersonCityNetwork", "$defs": {...}, ...}}'
        ```
      </Tab>

      <Tab title="Use with Cognify">
        ```bash theme={null}
        curl -X POST "http://localhost:8000/api/v1/cognify" \
          -H "Authorization: Bearer $TOKEN" \
          -H "Content-Type: application/json" \
          -d '{"datasets": ["my_dataset"], "custom_prompt": "<prompt from step 2>"}'
        ```
      </Tab>
    </Tabs>

    Optional `parameters` keys for the LLM endpoints include `temperature`, `max_tokens`, `top_p`, and `seed`.
  </Accordion>

  <Accordion title="Agent Management">
    The `/api/v1/agents` router exposes two groups of endpoints: **agent management**
    (create / list / get / delete an agent identity) and **agent connections**
    (register, unregister, and inspect live sessions). All endpoints require
    authentication. Agent identities are persisted as child users of the calling user,
    keyed by UUID (`agentId` in API responses), and authenticate to Cognee using the API key returned
    on creation — agents do not have passwords.

    | Endpoint                                    | Description                                                                                                                                                                                                                            |
    | ------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
    | `POST /api/v1/agents/create?name=<name>`    | Create an agent identity. Returns `agentId` (UUID), a synthesized `agentEmail`, and the one-time `agentApiKey`. Store the key — it is not retrievable later. Returns `409` if an agent with that name already exists for the caller.   |
    | `GET /api/v1/agents/list`                   | List agents created by the authenticated user. Each item includes `agentId`, `agentEmail`, and `apiKeyLabel`.                                                                                                                          |
    | `GET /api/v1/agents/{agent_id}`             | Fetch a single agent. `404` if not found, `403` if the caller does not own it.                                                                                                                                                         |
    | `DELETE /api/v1/agents/{agent_id}`          | Delete an agent. `404` / `403` as above.                                                                                                                                                                                               |
    | `POST /api/v1/agents/register`              | Register an agent connection (session). Body uses `RegisterAgentRequest` (see below). Returns the created `AgentConnection`. `201 Created`.                                                                                            |
    | `POST /api/v1/agents/unregister`            | Deactivate a connection. Body: `{ "agent_session_name": "<name>" }`. Returns `{ "activeAgents": <count> }`.                                                                                                                            |
    | `GET /api/v1/agents/connections`            | List agent connections visible to the caller. Filters: `agent_id`, `range` (`24h`/`7d`/`30d`/`all`, default `30d`), `status` (`active`/`inactive`/`unknown`), `include_sources`, `active_only`, `limit` (1–500, default 50), `offset`. |
    | `GET /api/v1/agents/connections/me`         | Connection detail for the authenticated user's own agent connection. Optional `agent_session_name` query filter. `404` if no matching connection.                                                                                      |
    | `GET /api/v1/agents/connections/{agent_id}` | Connection detail for a specific agent. Optional `agent_session_name` query filter.                                                                                                                                                    |

    **`RegisterAgentRequest` body fields:** `agent_session_name` (required — combined
    with the caller's user ID to form the connection ID), `type`
    (`sdk`/`api`/`mcp`/`claude_code`/`workflow`/`unknown`, default `api`),
    `memory_mode` (`session`/`cognee`/`hybrid`/`none`/`unknown`), `session_id`,
    `dataset_ids`, `dataset_names`, `source`, `origin_function`, `metadata`.

    <Tabs>
      <Tab title="Create an Agent">
        ```bash theme={null}
        curl -X POST "http://localhost:8000/api/v1/agents/create?name=my-agent" \
          -H "Authorization: Bearer $TOKEN"
        # {
        #   "agentId": "f3b0...-...",
        #   "agentEmail": "my-agent@cognee.agent",
        #   "agentApiKey": "ck_..."
        # }
        ```
      </Tab>

      <Tab title="Register a Connection">
        ```bash theme={null}
        curl -X POST "http://localhost:8000/api/v1/agents/register" \
          -H "Authorization: Bearer $TOKEN" \
          -H "Content-Type: application/json" \
          -d '{
            "agent_session_name": "my-agent-session",
            "type": "sdk",
            "memory_mode": "cognee",
            "dataset_names": ["project_docs"]
          }'
        ```
      </Tab>

      <Tab title="Unregister">
        ```bash theme={null}
        curl -X POST "http://localhost:8000/api/v1/agents/unregister" \
          -H "Authorization: Bearer $TOKEN" \
          -H "Content-Type: application/json" \
          -d '{"agent_session_name": "my-agent-session"}'
        # {"activeAgents": 0}
        ```
      </Tab>
    </Tabs>

    <Note>
      When the server runs in [agent mode](#agent-mode), `register` and `unregister`
      drive the auto-shutdown watchdog. The same `agent_session_name` registered twice
      by the same user counts as a single connection — registration is idempotent on
      the connection ID.
    </Note>
  </Accordion>

  <Accordion title="Multi-tenant Operations">
    **Create tenant:**

    ```bash theme={null}
    curl -X POST "http://localhost:8000/api/v1/permissions/tenants?tenant_name=acme" \
      -H "Authorization: Bearer $TOKEN"
    ```

    **Add user to tenant:**

    ```bash theme={null}
    curl -X POST "http://localhost:8000/api/v1/permissions/users/<user_id>/tenants?tenant_id=<tenant_id>" \
      -H "Authorization: Bearer $TOKEN"
    ```

    **Create role:**

    ```bash theme={null}
    curl -X POST "http://localhost:8000/api/v1/permissions/roles?role_name=editor" \
      -H "Authorization: Bearer $TOKEN"
    ```

    **Assign user to role:**

    ```bash theme={null}
    curl -X POST "http://localhost:8000/api/v1/permissions/users/<user_id>/roles?role_id=<role_id>" \
      -H "Authorization: Bearer $TOKEN"
    ```

    **Grant dataset permissions:**

    ```bash theme={null}
    curl -X POST "http://localhost:8000/api/v1/permissions/datasets/<principal_id>?permission_name=read&dataset_ids=<ds_uuid_1>&dataset_ids=<ds_uuid_2>" \
      -H "Authorization: Bearer $TOKEN"
    ```
  </Accordion>
</AccordionGroup>

<Columns cols={3}>
  <Card title="API Reference" icon="book" href="/api-reference/introduction">
    Explore all API endpoints
  </Card>

  <Card title="Setup Configuration" icon="settings" href="/setup-configuration/overview">
    Configure providers and databases
  </Card>

  <Card title="MCP Integration" icon="plug" href="/cognee-mcp/mcp-overview">
    Set up AI assistant integration
  </Card>
</Columns>
