> ## 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.

# Telnyx Connector

> Stream Telnyx call audio into a Zero Runtime room over TeXML media streaming. Create the connector with the Server SDK, configure Telnyx, and receive bidirectional audio.

A Telnyx connector streams live audio from a Telnyx call into a Zero Runtime room using [TeXML media streaming](https://developers.telnyx.com/docs/voice/programmable-voice/texml-setup). You point a Telnyx TeXML application at the connector, and Telnyx opens a bidirectional WebSocket that carries the call audio into the room. No SIP trunk is required.

Setup takes three steps: create the connector, configure your TeXML application, and route the call to a room. If you are new to connectors, read the [Connectors Overview](/telephony/connectors/overview) first.

## How It Works

1. A caller dials your Telnyx number.

2. Telnyx sends a TeXML voice webhook to your connector's webhook URL.

3. Zero Runtime resolves routing and responds with TeXML that tells Telnyx where to stream the audio:

   ```xml theme={null}
   <?xml version="1.0" encoding="UTF-8"?>
   <Response>
     <Start>
       <Stream url="wss://ingest.videosdk.live/telnyx?ref=<callRef>" track="both_tracks" bidirectionalMode="rtp" bidirectionalCodec="PCMU" />
     </Start>
     <Pause length="86400" />
   </Response>
   ```

4. Telnyx opens that WebSocket and streams audio. Zero Runtime claims the call, joins the room, and bridges audio in both directions. The `<Pause>` element keeps the call alive while streaming.

You do not implement the WebSocket protocol; Telnyx handles it. Audio is PCMU (G.711 μ-law) at 8 kHz, in 20 ms frames of 160 bytes. The call is identified by the `ref` value in the stream URL, because Telnyx exposes a `call_control_id` in its stream start event rather than the TeXML CallSid.

## Prerequisites

* A Zero Runtime account with an **API key and secret** from the [Zero runtime Dashboard](https://app.zeroruntime.ai/api-keys). The Server SDK signs and attaches its own management token on every request, so you never set an `Authorization` header yourself.
* An active Telnyx phone number.
* A Telnyx TeXML application, created under **Voice > TeXML** in the Telnyx Portal.

Install the Server SDK for your language:

<CodeGroup>
  ```bash Node.js theme={null}
  npm install @videosdk.live/server-sdk
  ```

  ```bash Go theme={null}
  go get github.com/videosdk-live/videosdk-server-sdk-go
  ```

  ```bash Rust theme={null}
  cargo add videosdk-server-sdk
  cargo add tokio --features rt-multi-thread,macros
  ```
</CodeGroup>

<Note>
  The Server SDK requires Node.js 18+, Go 1.23+, or Rust 1.75+. Keep your secret on the server — it signs tokens, so it must never reach a browser or mobile app.
</Note>

## Step 1: Create a Connector

Create the connector with a single Server SDK call. Setting the fallback `roomId` here is the fastest path to a working call, since every call then joins that room.

<CodeGroup>
  ```ts Node.js theme={null}
  import { VideoSDK } from "@videosdk.live/server-sdk";

  const client = new VideoSDK({
    apiKey: process.env.VIDEOSDK_API_KEY!,
    secret: process.env.VIDEOSDK_SECRET!,
  });

  const connector = await client.connectors.create({
    provider: "telnyx",
    roomId: "abcd-efgh-ijkl",
  });

  console.log(connector.webhookUrl); // set this on the TeXML application
  ```

  ```go Go theme={null}
  client, err := videosdk.NewClient(
  	videosdk.WithAPIKey(os.Getenv("VIDEOSDK_API_KEY")),
  	videosdk.WithSecret(os.Getenv("VIDEOSDK_SECRET")),
  )
  if err != nil {
  	log.Fatal(err)
  }
  ctx := context.Background()

  connector, err := client.Connectors.Create(ctx, videosdk.CreateConnectorParams{
  	Provider: videosdk.ConnectorTelnyx,
  	RoomID:   "abcd-efgh-ijkl",
  })
  if err != nil {
  	log.Fatal(err)
  }

  fmt.Println(connector.WebhookURL) // set this on the TeXML application
  ```

  ```rust Rust theme={null}
  use videosdk::{Client, ConnectorProvider, CreateConnectorParams};

  let client = Client::builder()
      .api_key("YOUR_API_KEY")
      .secret("YOUR_SECRET")
      .build()?;

  let connector = client
      .connectors()
      .create(CreateConnectorParams {
          provider: Some(ConnectorProvider::TELNYX),
          room_id: Some("abcd-efgh-ijkl".into()),
          ..Default::default()
      })
      .await?;

  println!("{:?}", connector.webhook_url); // set this on the TeXML application
  ```
</CodeGroup>

`connectors.create` accepts the following options.

| Option          | Required | Description                                                                                                                                      |
| :-------------- | :------- | :----------------------------------------------------------------------------------------------------------------------------------------------- |
| `provider`      | Yes      | Must be Telnyx: `"telnyx"` in Node.js, `videosdk.ConnectorTelnyx` in Go, `ConnectorProvider::TELNYX` in Rust.                                    |
| `name`          | No       | A label to help you recognize the connector later.                                                                                               |
| `roomId`        | No       | Fallback room that calls join when no routing rule matches. Set this for the simplest setup. It is returned on the connector as `defaultRoomId`. |
| `defaultRuleId` | No       | Fallback [routing rule](/telephony/call-routing/setting-up-routing-rules) ID, for dynamic routing.                                               |
| `region`        | No       | Pins the media and ingest region (e.g., `us002` or `in002`). When omitted, the region is derived from the caller.                                |

The call returns the connector, including the `webhookUrl` you need for the next step.

| Field           | Type   | Description                                                                                                              |
| :-------------- | :----- | :----------------------------------------------------------------------------------------------------------------------- |
| `id`            | string | Connector ID, prefixed with `cn_`. Use it to fetch, rotate, or delete the connector.                                     |
| `provider`      | string | Telephony provider — `telnyx` here.                                                                                      |
| `name`          | string | Display name.                                                                                                            |
| `webhookUrl`    | string | The URL you set as the TeXML application's voice webhook in the next step. It embeds the secret webhook key (`whk_...`). |
| `defaultRoomId` | string | Fallback room used when no routing rule resolves.                                                                        |
| `defaultRuleId` | string | Routing rule applied by default.                                                                                         |
| `region`        | string | Region call ingestion is pinned to.                                                                                      |
| `createdAt`     | string | Creation timestamp (ISO-8601).                                                                                           |

**Copy the `webhookUrl`.** You will set it on the TeXML application in Step 2.

<Warning>
  **Keep the webhook URL private.** Anyone who has the webhook URL can route calls into your room, because the key is part of the URL. If it leaks, [rotate the key](#rotate-the-webhook-key) to invalidate the old URL.
</Warning>

## Step 2: Configure Telnyx

Telnyx routes calls through a TeXML application. Point its voice webhook at the `webhookUrl` from Step 1, then assign your number to that application.

<Steps>
  <Step title="Open your TeXML application">
    In the [Telnyx Portal](https://portal.telnyx.com/), go to **Voice > TeXML Applications** and create or edit an application.
  </Step>

  <Step title="Set the voice webhook">
    Set the inbound **Voice webhook URL** to the `webhookUrl`, with the HTTP method set to **POST**, and save the application.
  </Step>

  <Step title="Assign your number to the application">
    Go to **Numbers > My Numbers**, open your number, assign it to the TeXML application, and save.
  </Step>
</Steps>

That is the entire provider-side setup. When the number rings, Telnyx posts to the webhook and Zero Runtime replies with the `<Start><Stream>` TeXML automatically.

## Step 3: Route the Call

Routing decides which room a call joins. You have three options, from simplest to most flexible:

* **Connector default.** The `roomId` you set in Step 1 sends every call to one fixed room. Best for a single destination or for testing.
* **Per-call override.** Append a `roomId` query parameter to the webhook URL (`...whk_xxx?roomId=<roomId>`) to target a specific room for that number.
* **Routing rules.** For different callers or numbers landing in different rooms, or to attach an AI agent, create a [routing rule](/telephony/call-routing/setting-up-routing-rules) and reference it with `defaultRuleId`.

If you set `roomId` in Step 1, you can skip this step and move straight to testing.

## Step 4: Test an Inbound Call

1. Add a participant or [AI agent](/telephony/call-routing/ai-agent-routing) to the target room, so there is audio to exchange.
2. Call your Telnyx number from any phone.
3. Confirm that the caller hears the room and the room hears the caller.

If you registered [lifecycle webhooks](#lifecycle-webhooks), you will see `call-started`, then `call-answered`, and finally `call-hangup` when the call ends. These are the quickest way to confirm the flow end to end.

## Manage the Connector

List your connectors, or fetch a single one by ID:

<CodeGroup>
  ```ts Node.js theme={null}
  await client.connectors.list();
  await client.connectors.get(connectorId);
  ```

  ```go Go theme={null}
  client.Connectors.List(ctx)
  client.Connectors.Get(ctx, connectorID)
  ```

  ```rust Rust theme={null}
  client.connectors().list().await?;
  client.connectors().get(connector_id).await?;
  ```
</CodeGroup>

### Rotate the Webhook Key

Rotating the key invalidates the current webhook URL immediately and returns a new one. Update the TeXML application with the new URL right after, or calls will stop reaching Zero Runtime.

<CodeGroup>
  ```ts Node.js theme={null}
  await client.connectors.rotateKey(connectorId); // invalidates the old webhook URL
  ```

  ```go Go theme={null}
  client.Connectors.RotateKey(ctx, connectorID) // invalidates the old webhook URL
  ```

  ```rust Rust theme={null}
  client.connectors().rotate_key(connector_id).await?; // invalidates the old webhook URL
  ```
</CodeGroup>

### Delete a Connector

<CodeGroup>
  ```ts Node.js theme={null}
  await client.connectors.delete(connectorId);
  ```

  ```go Go theme={null}
  client.Connectors.Delete(ctx, connectorID)
  ```

  ```rust Rust theme={null}
  client.connectors().delete(connector_id).await?;
  ```
</CodeGroup>

## Lifecycle Webhooks

To track calls on your server, register a webhook URL and listen for events such as `call-started`, `call-answered`, and `call-hangup`. Each request carries a `videosdk-signature` header (a base64 RSA-SHA256 signature of the body) so you can verify it. Connectors use the same webhook system as SIP, so see [SIP Webhooks](/telephony/managing-calls/webhooks) for the full event list, payloads, and registration.

## Troubleshooting

| Symptom                               | Likely cause and fix                                                                                                                                        |
| :------------------------------------ | :---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Call connects but there is no audio   | No one is in the target room, or the fallback `roomId` is wrong. Add a participant or agent and verify the room ID.                                         |
| Call ends immediately after answering | The number is not assigned to the TeXML application, or the webhook method is not POST. Recheck the application configuration and number assignment.        |
| The stream never starts               | The claim expired (more than 90 seconds), or routing resolved no room. Confirm the voice webhook is the current webhook URL and that a room is resolved.    |
| Connector calls fail with 401 or 403  | The API key or secret passed to the Server SDK client is missing or wrong. Check them in the [Zero runtime Dashboard](https://app.zeroruntime.ai/api-keys). |
| Audio works but quality is low        | Telephony audio is 8 kHz narrowband μ-law and PCMU by design. This is expected for PSTN calls.                                                              |

## Reference

* [Create a connector](https://docs.videosdk.live/api-reference/realtime-communication/connectors/create-connector)
* [List connectors](https://docs.videosdk.live/api-reference/realtime-communication/connectors/fetch-all-connectors)
* [Get a connector](https://docs.videosdk.live/api-reference/realtime-communication/connectors/fetch-connector)
* [Rotate the webhook key](https://docs.videosdk.live/api-reference/realtime-communication/connectors/rotate-connector-key)
* [Delete a connector](https://docs.videosdk.live/api-reference/realtime-communication/connectors/delete-connector)
