You have a Pipecat bot: a pipeline of frame processors connected to STT, an LLM, and TTS. You want it to answer real phone calls, and you do not want to operate a media server. The pipecat-telequick package runs your bot as an external agent. The external agent is a worker process. The worker dials one outbound QUIC/WebTransport session to ClutchCall. It authenticates with a media app key/secret. It registers under an agent handle. The engine routes each phone call to the worker through a VENDOR_BRIDGE agent config. For each call, the engine hands your bot a live, drop-in Pipecat transport. Your pipeline, services, aggregators, and event handlers run verbatim. Only the transport changes.
The worker is always the QUIC client. It dials out to :443 and opens no inbound ports. It runs behind NAT with no public URL and no tunnel.

What maps to what

Run the quickstart bot on a phone number

The runnable starter is a port of pipecat-quickstart. It is the official quickstart bot.py with one change: TeleQuickTransport replaces the Daily/WebRTC transport. It ships in the provider starters repo next to the telequick-agents SDK.
1

Install the packages

The quic extra installs the WebTransport client. Your Pipecat services (pipecat-ai[...] extras, provider keys) do not change.
2

Swap the transport in your bot

Your bot becomes a bot(transport, call) coroutine. The content inside it is the upstream quickstart, verbatim:
bot.py
run_pipecat_worker holds the session open. It invokes run_bot one time for each engine-assigned call, with a fresh transport bound to that call’s media.
Do not share stateful TransportParams (for example, VAD analyzers) across calls. Build them inside run_bot, or pass params_factory= to run_pipecat_worker. Then each call gets a fresh instance.
3

Create the external agent in the console

The console’s External agents create flow (agent.clutchcall.dev) does three tasks at the same time:
  • It reserves the agent handle that your worker registers under.
  • It mints the media app key/secret that the worker authenticates with.
  • It writes the VENDOR_BRIDGE agent config that routes calls to the worker:
agent-config.json
Export the credentials. AgentConfig.from_env() reads them:
4

Route a number and dial it

Attach the agent to an inbound DID or trunk in the same way as a native agent. See SIP Trunking. Dial the number. The engine dispatches the call to your worker. CDR / MOS / recording land in Observability in the same way as any call.

Troubleshooting

vendor_room in the agent config must exactly match the handle in TELEQUICK_AGENT. Presence is tied to the live session. Check that the worker logged a ready line after its most recent reconnect.
A resampling stage is skipped. The transport declares the call’s sample rate (8 kHz on PSTN) on transport.output(). If you construct your own TransportParams, do not set audio_out_sample_rate. It then inherits the call’s rate.
Media rides QUIC datagrams. Check that outbound UDP/443 to engine.clutchcall.dev is open. A network that permits TCP/443 but drops UDP completes presence and stalls media.

LiveKit integration

The same external-agent seam for LiveKit Agents workers.

Run a LiveKit Agent on the Transport

The end-to-end external-agent recipe on the same seam.

SIP Trunking

Bring a carrier trunk and route DIDs to your agents.

Custom Agent Runtime

The same worker pattern without Pipecat: raw frames in, raw frames out.