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

# Python SDK

> The official Python client for the SiteGPT API v2: sitegpt on PyPI.

`sitegpt` is the official SiteGPT SDK for Python — a small, dependable,
zero-dependency client for the [SiteGPT API v2](/docs/api-reference/v2/getting-started)
(standard library only, Python 3.9+).

* **Envelope-aware** — the API responds with `{ ok, data, meta }`; the SDK
  returns `data` directly (plain dicts and lists) and raises a `SiteGPTError`
  whenever `ok` is `false`.
* **Full API reach** — convenience methods cover the highest-value groups
  (chatbots, knowledge, conversations, leads, messages, onboarding); every
  one of the 119 API v2 operations is reachable through `request()`.

## Install

```sh theme={null}
pip install sitegpt
```

## Quickstart

Create a scoped API token on the [Agents page](/docs/developers/api-tokens-and-mcp), then:

```python theme={null}
import os

from sitegpt import SiteGPT

sitegpt = SiteGPT(api_token=os.environ["SITEGPT_API_TOKEN"])

# List your chatbots
chatbots = sitegpt.chatbots.list()["chatbots"]
chatbot_id = chatbots[0]["id"]

# Add knowledge to a chatbot
sitegpt.knowledge.add_links(
    chatbot_id, urls=["https://example.com/docs/getting-started"]
)

# Send a chat message (starts a new conversation)
reply = sitegpt.messages.send(chatbot_id, message="What are your pricing plans?")

# Review conversations and captured leads
conversations = sitegpt.conversations.list(chatbot_id, limit=20)
leads = sitegpt.leads.list(chatbot_id)
```

## Agent onboarding bootstrap (no token required)

The [agent-first onboarding](/docs/cli/onboarding) bootstrap is a public endpoint —
an AI agent can provision a SiteGPT workspace with no credentials at all, and
the response carries the temporary workspace token to use for everything that
follows:

```python theme={null}
from sitegpt import SiteGPT

# No API token yet — the bootstrap endpoint is public:
bootstrap = SiteGPT()
started = bootstrap.onboarding.start(websiteUrl="https://example.com")

# The response includes a temporary workspace token:
sitegpt = SiteGPT(api_token=started["apiToken"])
sitegpt.knowledge.document_stats(started["workspace"]["chatbotId"])
```

`health()` is public too; every other endpoint responds 401 until an
`api_token` is set.

## Error handling

Every failed call raises a `SiteGPTError` carrying the API's error envelope:

```python theme={null}
from sitegpt import SiteGPT, SiteGPTError

try:
    sitegpt.chatbots.get("nonexistent-id")
except SiteGPTError as error:
    print(error.status)      # HTTP status, e.g. 404
    print(error.code)        # machine-readable code, e.g. NOT_FOUND
    print(error.message)     # human-readable message
    print(error.hint)        # actionable next step, when the API provides one
    print(error.request_id)  # for support and debugging
```

## Convenience namespaces

| Namespace               | Methods                                                                                                                                                                                                                                                                                                                                    |
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `sitegpt.chatbots`      | `list`, `get`, `create`, `update`, `delete`, `dashboard`                                                                                                                                                                                                                                                                                   |
| `sitegpt.knowledge`     | `list_documents`, `get_document`, `update_document`, `delete_document`, `delete_documents`, `document_stats`, `resync_documents`, `add_links`, `add_website`, `add_sitemap`, `add_youtube`, `set_text`, `list_sources`, `get_source`, `create_source`, `update_source`, `revoke_source`, `ingest_source`, `list_sync_jobs`, `get_sync_job` |
| `sitegpt.conversations` | `list`, `get`, `create`, `update`, `delete`, `escalate`, `switch_to_ai`                                                                                                                                                                                                                                                                    |
| `sitegpt.leads`         | `list`, `get`, `update`, `delete`, `run_action`                                                                                                                                                                                                                                                                                            |
| `sitegpt.messages`      | `send`, `send_to_conversation`, `list`, `update`                                                                                                                                                                                                                                                                                           |
| `sitegpt.onboarding`    | `start`, `get_workspace`, `claim_workspace`, `delete_workspace`                                                                                                                                                                                                                                                                            |

Plus `sitegpt.me()` and `sitegpt.health()`.

### Destructive operations require confirmation

The API requires `confirm=true` on delete-family endpoints, and the SDK keeps
that intent explicit instead of confirming on your behalf: `chatbots.delete`,
`knowledge.delete_document`, `knowledge.delete_documents`,
`knowledge.revoke_source`, `conversations.delete`, and `leads.delete` take a
`confirm=True` keyword argument and raise a `CONFIRMATION_REQUIRED`
`SiteGPTError` client-side (before any request) without it:

```python theme={null}
sitegpt.conversations.delete(chatbot_id, thread_id, confirm=True)
sitegpt.chatbots.delete(chatbot_id, confirm=True)
```

Body fields and query filters are passed as keyword arguments using the API's
own field names (`camelCase`, exactly as documented in the OpenAPI document):

```python theme={null}
sitegpt.knowledge.list_documents(chatbot_id, limit=10, source=["WEBSITE"])
sitegpt.knowledge.get_document(chatbot_id, document_id, includeContent=True)
```

## Every other endpoint: `request()`

```python theme={null}
# Custom responses, personas, instructions, settings, members, tags, billing…
personas = sitegpt.request(f"/api/v2/chatbots/{chatbot_id}/personas")

sitegpt.request(
    f"/api/v2/chatbots/{chatbot_id}/settings",
    method="PATCH",
    body={"general": {"title": "Support Bot"}},
)
```

`request_with_meta()` additionally returns the envelope `meta` — including
`meta["nextCursor"]` for pagination:

```python theme={null}
data, meta = sitegpt.request_with_meta(
    f"/api/v2/chatbots/{chatbot_id}/conversations", query={"limit": 50}
)
if meta.get("nextCursor"):
    more = sitegpt.conversations.list(chatbot_id, cursor=meta["nextCursor"])
```

## Custom base URL

`base_url` defaults to `https://sitegpt.ai` and only needs to change if
SiteGPT gives you a different API origin.

## Related

* [TypeScript SDK](/docs/developers/sdk-typescript) — the same client for
  TypeScript and JavaScript.
* [SiteGPT CLI](/docs/cli/overview) — the same API from your terminal, scripts,
  and AI agents (includes a local MCP server).
* [API v2 reference](/docs/api-reference/v2/getting-started) — every endpoint,
  generated from the live OpenAPI document.
