Skip to main content
standin.plugins.cartesia puts Cartesia on a real Microsoft Teams call. StandIn answers the call and dials your worker; this plugin answers that dial, opens one session per call, and relays the audio both ways.

Install and run

There is nothing to install beyond the SDK. Cartesia is reached over an ordinary WebSocket, so this plugin adds no dependency and needs no extra.
Expose port 9442 at the /msteams/calling path and register the public wss:// URL as your StandIn identity’s agent voice URL. The full walkthrough is in the Quickstart, and there is a runnable example at examples/cartesia-msteams-connector.

The audio format

Audio is pinned to pcm_16000 in both directions. That is exactly what a Microsoft Teams call carries, so nothing resamples anything.

Your agent stays your agent

Cartesia runs the agent, so this plugin is transport and nothing else. There are no call tools to declare here, because whatever the agent does it does in its own code on Cartesia’s platform. What reaches that code:

Who is calling

Stream metadata: callId, callerName, tenantId, direction.

Call context

custom events: participant counts, recording changes, the closing line.

Key presses

Real dtmf events, read back out of the SDK’s own context sentence.
CARTESIA_SYSTEM_PROMPT is optional on purpose. Left unset, the agent keeps exactly the prompt you wrote on Cartesia’s side. Set it and the caller’s details are appended to yours. Nothing here ever silently rewrites a deployed prompt.

Inside your own worker

The plugin is a CallHandler like any other, so you can build it yourself instead of running the module:
Read the configuration once, then close over it. handler_factory runs once per call, so handler_factory=CartesiaHandler would call CartesiaConfig.from_env() again on every call: a key removed from the environment after startup would then fail the next caller instead of failing you. server.start() returns as soon as the listener is bound, so a script that ends there exits before a single call arrives. serve(), which is what python -m standin.plugins.cartesia runs, is the sample above plus an await asyncio.Event().wait() to hold the process open and an await server.aclose() in a finally, which drains live calls and releases the port on the way out.

Configuration

The configuration is read once when the worker starts, not per call, so a missing key stops the worker at startup rather than surprising the first caller. CARTESIA_API_HOST is checked against the cartesia.ai suffix, because your API key travels to it: a wrong host would be credential leakage rather than a failed call. The same shape applies to every plugin, and the reasoning is on Configuration.

Next

Realtime providers

The startup buffer, the echo guard and barge-in that every provider plugin sits on.

Configuration

Every STANDIN_ variable, and the helpers for reading your own.