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

# Run Your Agent

> Register and run your agent with serve, start sessions with invoke or the Dispatch API, and connect it to the phone network.

`zrt.serve()` runs your agent as a worker: it registers the agent under its `agent_id` with the Zero Runtime and serves a session to each caller. Fire `zrt.invoke()` from `on_ready` to launch a session and print a link you can open.

<CodeGroup>
  ```python title="main.py" Python theme={null}
  import zrt
  from zrt import Agent, Pipeline
  from zrt.plugins import DeepgramSTT, GoogleLLM, CartesiaTTS, TurnDetector
  from zrt.inference import AICousticsDenoise

  AGENT_ID = "assistant"

  pipeline = Pipeline(
      stt=DeepgramSTT(),
      llm=GoogleLLM(),
      tts=CartesiaTTS(),
      turn_detector=TurnDetector(model="echo-large"),
      denoise=AICousticsDenoise(model_id="quail-vf-2.2-l-16khz"),
  )


  class Assistant(Agent):
      def __init__(self) -> None:
          super().__init__(
              agent_id=AGENT_ID,
              instructions="You are a helpful assistant.",
              pipeline=pipeline,
          )


  if __name__ == "__main__":
      # Pass the class itself (not an instance): serve() builds a fresh Assistant +
      # pipeline per call, which is required for correct per-call state under concurrent calls.
      zrt.serve(Assistant, on_ready=lambda: zrt.invoke(AGENT_ID, room=zrt.Room(playground=True)))
  ```
</CodeGroup>

<CodeGroup>
  ```bash Python theme={null}
  python main.py
  ```
</CodeGroup>

`serve()` blocks and keeps the worker running, accepting a fresh session for every caller until you stop it. Scale out by running more `serve()` workers, each registering the same `agent_id`.

<Note>
  Pass the `Agent` subclass itself (`Assistant`, not `Assistant()`): `serve(Assistant)`. `serve()` accepts the class only, never a pre-built instance, and builds a fresh agent and pipeline per call, which is required for correct per-call state and pipeline hooks under concurrent sessions.
</Note>

## Start a session

`serve()` keeps your agent registered and idle. You then **start a session** to connect a caller to it. There are two ways, depending on where you're calling from:

| Method                        | Best for                                        | Called from             |
| :---------------------------- | :---------------------------------------------- | :---------------------- |
| **SDK: `zrt.invoke()`**       | Local development, scripts, CLIs, `on_ready`    | Your agent's codebase   |
| **Dispatch API: HTTP `POST`** | Production, remote triggers, Agent Cloud agents | Any language or service |

Both do the same thing: hand a session to a running worker registered under your `agent_id`. Use whichever fits where you start the session.

### Invoke with the SDK

During development, call `zrt.invoke()` from a script, a CLI, a web handler, or your agent's `on_ready` hook. It returns the session details (`session_id`, `room_id`, `worker_id`), plus a `playground_url` when the room has `playground=True` (the default). Open it to talk to your agent right away.

<CodeGroup>
  ```python title="main.py" Python theme={null}
  import zrt

  # Invoke a playground session and print a link to talk to the agent.
  result = zrt.invoke("assistant", room=zrt.Room(playground=True))
  print(result["playground_url"])
  ```
</CodeGroup>

#### Place a phone call

Pass `Sip(...)` to start the session on an outbound (or inbound) call instead of a playground room:

<CodeGroup>
  ```python Python theme={null}
  zrt.invoke(
      "assistant",
      sip=zrt.Sip(call_to="+1XXXXXXXXXX", call_from="+1XXXXXXXXXX"),
  )
  ```
</CodeGroup>

### Dispatch with the API

In production, start a session over HTTP with the Dispatch API. It needs no SDK, works from any language or service, and supports both Agent Cloud and self-hosted agents, for both playground and SIP-connected sessions.

<Note>
  `meetingId` and `room_id` (the SDK's `Room(room_id=...)`) are the same identifier. The Dispatch API just calls it `meetingId`. Pass a room ID you already have, or omit it to auto-create one.
</Note>

#### Endpoint

```bash theme={null}
POST https://api.videosdk.live/v2/agent/dispatch
```

#### Request body parameters

| Parameter    | Type   | Required | Description                                                                                                                                   |
| :----------- | :----- | :------- | :-------------------------------------------------------------------------------------------------------------------------------------------- |
| `meetingId`  | string | Yes      | The room ID to dispatch the agent into (same value as the SDK's `room_id`).                                                                   |
| `agentId`    | string | Yes      | The ID of the agent to dispatch.                                                                                                              |
| `metadata`   | object | No       | Optional metadata to pass to the agent, such as variables.                                                                                    |
| `versionTag` | string | No       | The specific commit version of an Agent Cloud agent to dispatch. If omitted, the latest deployed version is used. Not for self-hosted agents. |

#### Example request

```bash theme={null}
curl -X POST "https://api.videosdk.live/v2/agent/dispatch" \
  -H "Authorization: YOUR_ZRT_AUTH_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "meetingId": "xxxx-xxxx-xxxx",
    "agentId": "ag_xxxxxx",
    "metadata": {
        "variables":[
            {
                "name":"fname",
                "value":"john"
            }
        ]
    },
    "versionTag":"cm_xxxxxx"
  }'
```

#### Responses

**On success**, the request returns a confirmation that the dispatch has been initiated:

```json theme={null}
{
    "message": "Agent dispatch requested successfully.",
    "data": {
        "success": true,
        "status": "assigned",
        "roomId": "xxxx-xxxx-xxxx",
        "agentId": "ag_xxxxxx"
    }
}
```

**On error**, you receive one of the following:

<Tabs>
  <Tab title="No Workers Available">
    No servers and agents are configured to handle the request.

    ```json theme={null}
    { "message": "No workers available" }
    ```
  </Tab>

  <Tab title="No Workers Registered">
    Specific to self-hosted agents: the `agentId` is valid, but no server has registered for it.

    ```json theme={null}
    { "message": "No workers have registered with agentId 'ag_xxxxxx'" }
    ```
  </Tab>

  <Tab title="Agent Not Deployed">
    Specific to Agent Cloud agents: the agent exists but has no deployed version available for dispatch.

    ```json theme={null}
    { "message": "No agent is deployed with agentId 'ag_xxxxxx'" }
    ```
  </Tab>
</Tabs>

## Inside the session

However you started it, once a session is live you control it from the agent's hooks and tools. Reach it as `self.session`:

| Method                | What it does                          |
| :-------------------- | :------------------------------------ |
| `say(text)`           | Speak a fixed line (straight to TTS). |
| `reply(instructions)` | Generate a reply through the LLM.     |
| `close()`             | End the session and run `on_exit()`.  |

<CodeGroup>
  ```python Python theme={null}
  async def on_enter(self):
      await self.session.say("Hi! How can I help?")
  ```
</CodeGroup>

## Connect your agent to the phone network

With your agent running locally, connect it to the outside world by setting up gateways and routing rules in your Zero Runtime Dashboard or via the Zero Runtime API.

<Tabs>
  <Tab title="Via Dashboard">
    <Steps>
      <Step title="Add SIP Configuration">
        * Go to the Zero Runtime Dashboard.
        * Click on **Add Number**.
        * Click on **Configure SIP**.
        * Give a name and add your phone number.

        <video autoPlay loop muted controls className="w-full aspect-video rounded-xl" src="https://assets.videosdk.live/images/setup.mp4" />
      </Step>

      <Step title="Setup Inbound Gateway">
        * Copy the **Inbound URL** from the Zero Runtime Dashboard.
        * Go to Twilio and create a new SIP Trunk.
        * Go to the **Origination** section, paste the Inbound URL there, and save it.

        <video autoPlay loop muted controls className="w-full aspect-video rounded-xl" src="https://assets.videosdk.live/images/inbound-gateway.mp4" />
      </Step>

      <Step title="Setup Outbound Gateway">
        * Go to the **Termination** section in Twilio, create a URI, and paste it into the outbound section in the Zero Runtime Dashboard.
        * Create a username and password in Twilio and add it to the Zero Runtime outbound section.

        <video autoPlay loop muted controls className="w-full aspect-video rounded-xl" src="https://assets.videosdk.live/images/outbound-gateway.mp4" />
      </Step>

      <Step title="Setup Routing Rules">
        * Click on **Configure rule** then **Create new routing rule**.
        * Add **Routing Rule Name**.
        * Select **API Key**.
        * Add **Call Direction** (Inbound or Outbound).
        * Add **Phone Number**.
        * Add **Room Type**.
        * Add **Agent ID**.
        * Click **Save**.

        <video autoPlay loop muted controls className="w-full aspect-video rounded-xl" src="https://assets.videosdk.live/images/routing-rules.mp4" />
      </Step>
    </Steps>
  </Tab>

  <Tab title="Via API">
    <Steps>
      <Step title="Create Phone Number">
        Register your phone numbers and provision inbound and outbound SIP gateways in a single request. Replace `$YOUR_TOKEN` and update the phone numbers, SIP region, and outbound gateway settings for your provider.

        ```bash theme={null}
        curl -H 'Authorization: $YOUR_TOKEN' \
          -H 'Content-Type: application/json' \
          -d '{
            "name": "My SIP Setup",
            "phoneNumbers": [
              "+14155551234",
              "+14155555678"
            ],
            "isShared": true,
            "mediaEncryption": "disable",
            "inbound": {
              "sipRegion": "us002"
            },
            "outbound": {
              "sipRegion": "us002",
              "address": "sip.telnyx.com:5061",
              "transport": "tls",
              "auth": {
                "username": "sip-user",
                "password": "sip-pass"
              }
            }
          }' \
          -X POST https://api.videosdk.live/v2/sip/phone-numbers
        ```

        API reference: [Create Phone Numbers + SIP Gateways](https://docs.videosdk.live/api-reference/realtime-communication/sip/phone-numbers/create-phone-number).
      </Step>

      <Step title="Create Routing Rule">
        Create a routing rule to route inbound calls to your agent. Set `agentId` to your agent's ID (from above) and replace `$YOUR_TOKEN`, `$YOUR_API_KEY`, and the phone numbers with your own values.

        ```bash theme={null}
        curl -H 'Authorization: $YOUR_TOKEN' \
          -H 'Content-Type: application/json' \
          -d '{
            "name": "Inbound support rule",
            "type": "inbound",
            "phoneNumbers": [
              "+14155551234"
            ],
            "apiKey": "$YOUR_API_KEY",
            "agentId": "$YOUR_AGENT_ID",
            "agentMetadata": {
              "team": "support"
            },
            "room": {
              "type": "dynamic",
              "prefix": "blank"
            },
            "includeHeaders": "SIP_X_HEADERS",
            "headersToAttributes": {
              "X-Caller-Id": "callerId"
            },
            "headers": {
              "X-Customer-Id": "cust_42"
            },
            "allowedNumbers": [],
            "allowedIpAddresses": [],
            "tags": [
              "support",
              "v2"
            ],
            "recording": false,
            "dtmf": false,
            "noiseCancellation": false,
            "hidePhoneNumber": true
          }' \
          -X POST https://api.videosdk.live/v2/sip/routing-rule
        ```

        API reference: [Create Routing Rule](https://docs.videosdk.live/api-reference/realtime-communication/sip/routing-rules/create-routing-rule).
      </Step>
    </Steps>
  </Tab>
</Tabs>

You have now configured Zero Runtime to route inbound calls from your configured phone number(s) to your running agent.

## Make and receive calls

Your setup is complete. Test it out.

<Tip>
  Make sure your AI agent is running locally before configuring the telephony settings. The agent must be active to receive incoming calls.
</Tip>

### Making an inbound call

* Using any phone, dial the SIP number you configured.
* Your local agent will automatically answer.
* You'll hear the greeting: "Hello! I'm your real-time assistant. How can I help you today?"
* Start talking. The agent will listen and respond in real time.

### Making an outbound call

Trigger an outbound call from your agent with a simple API request. Use `curl` or any API client to make a `POST` request to the Zero Runtime API. Replace `$YOUR_TOKEN` and the `routingRuleId` with your own.

```bash theme={null}
curl -H 'Authorization: $YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
    "sipCallFrom" : "+14155550100",
    "sipCallTo" : "+14155550199",
    "routingRuleId" : "rr_2554md"
  }' \
  -X POST https://api.videosdk.live/v2/sip/call
```

This commands your agent to dial the specified number and start a conversation.

<Tip>
  For optimal performance, run your agent in the same geographic region as your SIP provider (for example, US East for Twilio, US West for Telnyx, Europe for Plivo). This reduces latency and improves call quality.
</Tip>

## What's Next

<CardGroup cols={2}>
  <Card title="Create an Agent" icon="robot" href="/build/creating-an-agent">
    Define the agent that serve runs.
  </Card>

  <Card title="Tools and Capabilities" icon="wrench" href="/build/tools-and-capabilities/overview">
    Give the agent function tools and external services.
  </Card>

  <Card title="Telephony" icon="phone" href="/build/telephony/overview">
    DTMF, call transfer, and voicemail detection.
  </Card>

  <Card title="Deploy an Agent" icon="rocket" href="/deployments/deploy-an-agent">
    Take your agent to production.
  </Card>
</CardGroup>

## References

<Tabs>
  <Tab title="Python">
    #### Examples

    <CardGroup cols={2}>
      <Card title="Cascade Basic" icon="github" href="https://github.com/ZeroRuntimeAI/zrt-python-sdk-examples/blob/main/features/basic_cascade.py">
        Smallest complete agent showing serve + invoke.
      </Card>
    </CardGroup>

    #### SDK Reference

    <CardGroup cols={2}>
      <Card title="_serve.py" icon="book" href="/api-reference/python/core/agent-and-session">
        `_serve.py` in the Python API reference.
      </Card>

      <Card title="_invoke.py" icon="book" href="/api-reference/python/core/agent-and-session">
        `_invoke.py` in the Python API reference.
      </Card>
    </CardGroup>
  </Tab>
</Tabs>
