plugins.entries."msteams-voice".config in your OpenClaw config.
sharedSecret must match the secret you set in StandIn for the hosted bridge that connects to
this plugin’s media WebSocket.
Mode selection
Setmode to "realtime" or "streaming". If omitted, the runtime auto-selects realtime when a
realtime provider resolves, else streaming. Both modes honor the inbound allowlist, outbound
call-backs, recording gate, and sessionScope agent memory. See Modes.
stt.provider / stt.providers if set, else your
openclaw-configured transcription provider; if none resolves it falls back to VAD-segmented file
transcription. The realtime.* block is ignored except the echo-guard knobs
(suppressInputDuringPlayback, echoSuppressionWindowMs, echoBargeInRms), which apply in both modes.
Outbound call-backs (optional, either mode)
placeCall(userObjectId, { message, mode }) is implemented on the runtime (no-answer / declined →
voicemail / no-answer); the outbound block enables it.
workerBaseUrl is StandIn’s outbound API URL from your dashboard - not a server you host.Key reference
What
inboundPolicy: "pairing" actually does today. The plugin issues no pairing codes,
expirations, or approval prompts for inbound calls: with "pairing", a caller is accepted only
if their AAD object id (or phone number) is already in allowFrom - exactly the same check as
"allowlist". A rejected caller is logged with their caller id and the call is closed. The
openclaw pairing approve msteams ... flow you may know from the chat channel manages chat DM
approvals only; it does not populate this voice allowFrom. Until a real call-pairing flow ships,
prefer "allowlist" and manage allowFrom yourself; "pairing" is accepted so such configs keep
working with identical (allowlist) behavior.