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

# Python SDK

> Check planned Python SDK availability and read Threetone agent records with a validated Requests example.

Read agent records from a server-side Python script using Requests. This example checks your API key, limits network waits, validates the response fields it uses, and supports pagination.

<Note>
  The first-party Threetone Python SDK is planned. No verified installable release has been identified. `requests` is an HTTP library, and the example below calls the public REST API directly.
</Note>

## Before you start

Use a supported Python release and a personal [API key](/overview/administration/workspaces/api-keys) with permission to read agents. Set `THREETONE_API_KEY` in the environment where your script runs. Keep it out of source files and logs.

Install the HTTP dependency:

```bash theme={null}
python -m pip install requests
```

## Read a page of agents

Save this as `list_agents.py`. It reads up to 20 agents through [List agents](/api-reference/agents-platform/list-agents).

```python list_agents.py theme={null}
import os

import requests

api_key = os.environ.get("THREETONE_API_KEY")
if not api_key or not api_key.strip():
    raise RuntimeError("Set THREETONE_API_KEY in your server environment.")


def list_agents(cursor=None):
    params = {"page_size": 20}
    if cursor is not None:
        params["cursor"] = cursor

    try:
        response = requests.get(
            "https://api.threetone.in/v1/convai/agents",
            headers={"x-api-key": api_key},
            params=params,
            timeout=(5, 30),
            allow_redirects=False,
        )
    except requests.RequestException:
        raise RuntimeError(
            "GET /v1/convai/agents failed before a usable response arrived."
        ) from None

    request_id = response.headers.get("X-Request-Id", "unavailable")[:128]
    context = (
        f"GET /v1/convai/agents status={response.status_code} "
        f"request_id={request_id!r}"
    )
    if response.status_code != 200:
        raise RuntimeError(context)

    try:
        page = response.json()
    except ValueError:
        raise RuntimeError(f"Invalid JSON; {context}") from None

    if not isinstance(page, dict) or not isinstance(page.get("agents"), list):
        raise RuntimeError(f"Invalid agents response; {context}")
    if type(page.get("has_more")) is not bool:
        raise RuntimeError(f"Invalid pagination response; {context}")
    next_cursor = page.get("next_cursor")
    if next_cursor is not None and not isinstance(next_cursor, str):
        raise RuntimeError(f"Invalid cursor; {context}")
    if page["has_more"] and not next_cursor:
        raise RuntimeError(f"Missing next cursor; {context}")
    for agent in page["agents"]:
        if (
            not isinstance(agent, dict)
            or not isinstance(agent.get("agent_id"), str)
            or not isinstance(agent.get("name"), str)
        ):
            raise RuntimeError(f"Invalid agent entry; {context}")

    return page["agents"], page["has_more"], next_cursor


agents, has_more, next_cursor = list_agents()
for agent in agents:
    print(agent["agent_id"], agent["name"])
print("More agents available:", has_more)
```

Run the script in the environment that contains your key:

```bash theme={null}
python list_agents.py
```

A successful request prints the ID and name of each returned agent, followed by whether another page is available. An empty list prints no agent rows. The example checks only the fields it consumes, not the complete response schema.

The timeout sets a five-second connection wait and a 30-second read inactivity limit. It is not a deadline for the entire download. Redirects are disabled to avoid forwarding the API key to another destination.

## Read the next page

When `has_more` is true, call `list_agents(cursor=next_cursor)` to read the next page. Continue with each newly returned cursor until `has_more` is false. Do not alter or construct cursor values.

`page_size` accepts 1 to 100 and defaults to 30 when omitted. The example uses 20. If you add filters, keep them the same while following a cursor. Use [Get agent](/api-reference/agents-platform/get-agent) when you need one agent's complete saved configuration.

## Troubleshoot a request

For `401`, check the key and its expiry. For `403`, check its permissions and workspace access. For `429`, follow `Retry-After` when supplied. See [Errors and retries](/api-reference/errors) before adding automatic retries.

The error context includes the method, path, status, and an escaped request ID limited to 128 characters. It excludes the key and response body. A connection failure or timeout may have no response status or request ID.

## Frequently asked questions

<AccordionGroup>
  <Accordion title="Is requests the Threetone SDK?" id="faq-python-library">
    No. It is a general-purpose Python HTTP library. The Threetone Python SDK is planned, and no first-party package name is documented for installation yet.
  </Accordion>

  <Accordion title="Does this example create or change an agent?" id="faq-python-read-only">
    No. It sends a GET request and reads existing records. A successful read does not start a conversation or verify execution availability.
  </Accordion>

  <Accordion title="Why is my agent list empty?" id="faq-python-empty">
    Confirm that the key belongs to the intended workspace and can access its agents. The list excludes archived agents by default. Check the filters in [List agents](/api-reference/agents-platform/list-agents).
  </Accordion>
</AccordionGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.