An external agent is a voice agent that you run yourself — a LiveKit Agents worker or any comparable framework — outside the TeleQuick engine. The engine still owns the call. Media rides TeleQuick QUIC into a WebTransport endpoint your worker connects back to, so there is no WebRTC hop and no vendor cloud in the media path. Creating one produces two things:
  • an agent_config row with an external_handle set, and
  • a media_app credential (an app key plus a secret).
Both are minted by mediaApps.provision. This page covers the handle grammar, the credential lifecycle, what the provision response does and does not contain, how worker presence is determined, and the bulk importer.

What an external agent is

An in-engine agent is built from a template: adminAgents.createConfig stores a system prompt and welcome message and the engine runs the ASR/LLM/TTS pipeline. An external agent is created as a plain draft agent_config row with no in-engine pipeline; mediaApps.provision then marks it external and hydrates the VENDOR_BRIDGE pipeline, which is what tells the engine to bridge the call out over /media/ instead of running its own turn loop. Everything else about the object is unchanged. An external agent is still an agent_config row, so it carries the same resource tags, appears in Test Drive, and sits behind the same trunks, numbers, dispatch, recordings and call-record surfaces as any other agent.

The handle and why it must be unique

The handle is the token your agent registers as over TeleQuick QUIC. It is used as the vendor-room / presence suffix, so it is the key the platform matches a connected worker against. Grammar: lowercase letters, digits, ., _ and -. When the console derives a handle from a display name it lowercases the name, collapses every run of disallowed characters into -, strips leading and trailing -, and truncates to 64 characters.
Handles must be unique within the org. A duplicate handle breaks presence for both agents that share it, because a connected worker can no longer be attributed to a single agent. The bulk importer therefore validates each row against the handles already in use and rejects a collision before it writes anything. To change a handle after the fact, edit it inline on the external-agents list. Saving calls mediaApps.provision again with the new handle. Treat this as a deliberate action: presence keys and any vendor-side configuration are built from the handle, so renaming one that is live will disconnect the deployment until the worker is reconfigured.

Provision, rotate, revoke, re-provision

Four procedures cover the whole lifecycle. All of them are org-scoped. Provision creates the credential, sets the handle on the agent, and sets the VENDOR_BRIDGE pipeline. It is also the re-provision path: call it again for an agent whose credential was revoked, or whose credential was never minted because provisioning failed partway through an import. When you re-provision, pass the agent’s existing external_handle rather than a fresh one, so the customer’s deployment keeps working. Rotate issues a new secret for the existing credential. The current secret stops working once the engine reloads, so rotate during a window where the worker can be restarted with the new value. Revoke marks the credential revoked. The agent keeps its handle and its row, and cannot connect until it is provisioned again. Revoke is not a one-way door — the external-agents screen shows an Issue credential button for any external agent with no live credential, and that button is mediaApps.provision with the preserved handle. The list shows two independent states per row: the credential status (active, or revoked when there is no live media_app row) and, when a credential exists, worker presence.

Connect URL, app key, and secret handling

provision and rotateSecret return a mediaPath. The connect URL is that path on the engine host, over WebTransport:
The console derives <engine-host> from the hostname of the deployment’s configured QUIC URL, so a white-labelled or self-hosted deployment gets its own host without any change to the credential. You leave the dialog with four values: secret is only present when the call actually created the credential. If you call provision for an agent that already has a live credential, the response carries the handle, key and path but no secret — there is nothing to reveal, because the stored value is sealed. The console surfaces this as “This agent already had an active credential. Use Rotate to issue a new secret.” Rotating is the only way to obtain a cleartext secret for an existing credential. The same rule applies to the reveal panel after a rotate: it is shown once, on that screen, and is not recoverable by reloading. Copy it before you navigate away. If it is lost, rotate again.

Pointing an existing agent framework at the transport

An unmodified LiveKit Agents worker connects through the livekit-plugins-telequick transport plugin. Give it the three values from the reveal panel — connect URL, app key and secret — and the handle it should register as. No WebRTC and no LiveKit cloud is involved: the plugin speaks the /media/ endpoint directly.

Worker presence and what it does not tell you

mediaApps.presenceAll returns one { id, connected } entry per external agent in the org, in a single batched call. The external-agents screen polls it every 5 seconds, so a worker you start in another terminal appears without reloading the page. Presence and credential status answer different questions:
  • Credential active means the platform would accept a connection. It says nothing about whether anyone is on the other end.
  • connected: true means a worker is currently attached for that agent.
A call dispatched to an agent whose worker is absent is dead air, which is why the presence pill is rendered separately, and why the presence pill is hidden entirely for an agent with no credential — there is nothing to connect with yet. Test Drive for an external agent applies the same rule: the worker-presence pill is shown and Start is gated on it.

Bulk import: CSV columns and the credentials file

Standing up a fleet through a modal, four copied values at a time, does not scale. The Bulk import button on the external-agents screen takes a CSV and walks away with one credentials file. Download the template (telequick-external-agents-template.csv) from the dialog to get the exact column set. Each row supplies the agent name, plus a handle; when the handle cell is blank the importer derives the effective handle from the name using the slug rule above. Rows are validated before anything is written, including against the handles already in use in the org. Each row is imported in two steps, in this order:
  1. adminAgents.createConfig({ orgId, name }) — the draft agent row.
  2. mediaApps.provision({ orgId, agentConfigId, handle }) — the credential.
The order is deliberate. If step 2 fails, the agent row survives as an ordinary non-external draft that you can see and fix, rather than leaving a credential with no agent behind it. The importer then offers a results CSV (telequick-external-agent-credentials.csv) with one row per imported agent: This file is the only copy of those secrets. Treat it as a secret file, distribute it over a channel you trust, and rotate any credential whose row you cannot account for.

Tags delivered to your worker as call.tags

External agents are agent_config rows, so they take the same resource tags as in-engine agents (kind: 'agent_config'). The external-agents list resolves tags for the whole page in one bulk call and exposes the same tag editor inline. Tags are not cosmetic here: the engine forwards the agent’s effective tags to your worker on job_assign as call.tags. That is the supported way to hand per-agent metadata — environment, team, customer, routing hints — to a worker you host yourself, without baking it into the worker’s own configuration.

Where this lives in the console

Rotate and revoke are reachable only from the external-agents screen. That screen is the home for the credential lifecycle — if a secret leaks, that is where you replace it.
  • Authentication — how server keys, relay tokens and secrets differ
  • Telemetry — CDRs and metrics for calls handled by an external agent