- an
agent_configrow with anexternal_handleset, and - a
media_appcredential (an app key plus a secret).
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.
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:
<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 thelivekit-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
activemeans the platform would accept a connection. It says nothing about whether anyone is on the other end. connected: truemeans a worker is currently attached for that agent.
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:
adminAgents.createConfig({ orgId, name })— the draft agent row.mediaApps.provision({ orgId, agentConfigId, handle })— the credential.
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 areagent_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.
Related
- Authentication — how server keys, relay tokens and secrets differ
- Telemetry — CDRs and metrics for calls handled by an external agent