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

# Call from Python

> Call a deployed agent from Python with httpx: stream its reply, show its tool calls, and handle a failure mid stream.

This is the Python snippet from your agent's page in the dashboard, which fills in the agent's URL for you. It uses [httpx](https://www.python-httpx.org), and there is no Onecortex SDK to install.

## Before you begin

* A deployed agent and its ID, from its page in the dashboard.
* An [API key](/call/api-keys) in `ONECORTEX_API_KEY`.
* `pip install httpx`.

## Stream the reply

Replace `agt_...` with your agent's ID:

```python invoke.py theme={null}
import json, os, httpx

with httpx.stream(
    "POST", "https://api.onecortex.io/v1/agents/agt_.../invoke",
    headers={"Authorization": f"Bearer {os.environ['ONECORTEX_API_KEY']}"},
    json={"prompt": "hello", "stream": True},
) as response:
    event = None
    for line in response.iter_lines():
        if line.startswith("event: "):
            event = line[7:]
        elif line.startswith("data: "):
            data = json.loads(line[6:])
            if event == "text":
                print(data["delta"], end="", flush=True)
            elif event == "tool_call_start":
                print(f"[calling {data['name']}]")
            elif event == "done":
                print()
            elif event == "error":
                # Handle this, or a failure looks like an empty success.
                raise RuntimeError(data["message"])
```

For the [quickstart's](/quickstart) `echo` agent:

```text Output theme={null}
[calling word_count]
You said: hello
```

httpx waits 5 seconds for data by default, and an agent can think for longer than that before its first token. For a long running agent pass `timeout=None`, or a timeout longer than 15 seconds: Onecortex keeps an idle stream alive with a comment line every 15 seconds.

<Warning>
  A stream that has started has already sent `200 OK`, and cannot change it. If the run fails after that, the failure arrives in the stream as `event: error`. Handle it: a client that reads only `text` and `done` shows a failed run as an empty success.
</Warning>

## Get one JSON response

Leave out `"stream": True` to wait for the whole run and get one body:

```python invoke_json.py theme={null}
import os, httpx

response = httpx.post(
    "https://api.onecortex.io/v1/agents/agt_.../invoke",
    headers={"Authorization": f"Bearer {os.environ['ONECORTEX_API_KEY']}"},
    json={"prompt": "hello"},
    timeout=None,
)
body = response.json()
if response.is_error:
    # A failed run and a refused request both carry `error`.
    raise RuntimeError(body["error"]["message"])
print(body["result"])
```

```text Output theme={null}
You said: hello
```

Every field of the body is on [the invoke API](/call/invoke).

## Continue a conversation

Send the same `sessionId` on each call to reach the same running instance of your agent:

```python theme={null}
json={"prompt": "When will it arrive?", "sessionId": "user-42", "stream": True}
```

See [Sessions](/build/sessions) for what a session keeps, and what it does not.
