Skip to main content
Custom Text-to-Speech lets you connect Rapida to a WebSocket speech synthesis service that is not available as a built-in TTS provider. You provide the provider endpoint, authentication headers, output audio format, and a JSON DSL that tells Rapida how to send assistant text and how to read provider audio, done, and error responses. Use Custom TTS when your provider can receive text over WebSocket and return audio as one of the following:
  • Binary WebSocket frames containing raw audio.
  • JSON WebSocket messages containing base64-encoded audio.
Provider identifier: custom-tts API compatibility: websocket_v1
Custom TTS is configured from credentials and assistant voice output settings. You do not need to write a new Rapida transformer when the provider protocol can be described with the DSL on this page.

Setup flow

1

Confirm the provider protocol

Custom TTS supports websocket_v1. Your provider must accept a WebSocket connection and return audio or status messages over that same connection.
2

Create the Custom TTS credential

Open Credentials or Integrations > Models, choose Custom TTS, and create a credential with apiCompatibility, baseUrl, and any required headers.
3

Select Custom TTS for voice output

Open the assistant or deployment voice settings, go to Voice Output, and select Custom TTS as the text-to-speech provider.
4

Set the output audio format

Choose the audio encoding and sample rate returned by your provider.Rapida interprets provider audio using these values, then resamples it to Rapida’s internal audio format when needed.
5

Write the DSL configuration

Fill speak.query_params, speak.request_rules, and speak.response_rules.Query parameters build the provider WebSocket URL. Request rules map Rapida text lifecycle packets to outbound provider frames. Response rules map provider frames to audio, done, or error events.
6

Test speech and interruption

Run a test conversation. Confirm that audio plays, done events end the response cleanly, and interruption stops any queued provider audio.

Credential fields

Create one credential for the external TTS provider. The runtime also accepts snake case credential keys: api_compatibility and base_url.
Headers are static credential values. The DSL cannot template headers, read environment variables, sign requests, or change the WebSocket path dynamically.

Assistant TTS arguments

These fields are configured on the assistant or deployment voice output provider. The UI stores them with the provider metadata, and the runtime reads the option keys shown below.
The UI exposes the audio and DSL fields. speak.voice.id, speak.model, and speak.language are optional metadata keys for API-driven or imported configurations. If your provider needs fixed voice, model, or language values and those fields are not available in your UI, put the values directly in query params or request rules.
When you work with raw assistant metadata, use the unprefixed custom TTS option keys, such as speak.request_rules. The UI may preserve other speaker-level settings under speaker.*, but the custom TTS DSL fields are the speak.* keys listed above.

DSL overview

Custom TTS has three DSL sections. The DSL is intentionally small. It does not run JavaScript, call functions, perform regex matching, concatenate strings, perform compound conditions, read environment variables, or compute authentication signatures.

Query parameters

Use speak.query_params when your provider expects configuration in the WebSocket URL.

Query variable reference

Query parameter expressions can use $var to read these variables.

Query parameter rules

  • speak.query_params must be a JSON object.
  • The object must be flat. A query parameter value cannot be a nested object or array unless that object is a supported DSL expression.
  • Each rendered value must be a primitive supported by the UI validator: string, number, or boolean.
  • Existing query parameters in baseUrl are preserved unless speak.query_params renders the same key.
  • A key that starts with $ is treated as an unsupported operator and is rejected.
  • text is not a supported query parameter variable. Use packet.text in request rules.
This configuration:
can produce a provider URL like:

Request rules

speak.request_rules is an ordered JSON array. Each rule has a when block and a send block.

Request packet reference

Request frame reference

Every matching request rule for a packet is sent in order. This lets one text, done, or interrupt packet produce more than one provider message when required.

Request scope

Request rules use $path to read from the request scope. For text:
For done and interrupt, packet.text is present but may be empty:

Request path reference

One-shot synthesis example

Use this when the provider synthesizes each text packet immediately.

Text, done, and interrupt example

Use this when the provider expects text payloads, an explicit final message, and an explicit cancel message.
Add an interrupt rule if your provider needs an explicit cancel or clear message. Rapida sends the matching interrupt request first, then closes the WebSocket connection.

Response rules

speak.response_rules is an ordered JSON array. Each provider WebSocket response is parsed into a binary, json, or text frame, then the first matching response rule is evaluated. Custom TTS response rules support binary and json; text responses are ignored unless you change the provider to send JSON status messages.

Response frame parsing

Response matching

For JSON rules, when.path and when.equals must be provided together. when.equals must be a primitive JSON value: string, number, boolean, or null. For binary rules, when.path and when.equals are not allowed.

Emit keys

If a response rule emits error, Rapida emits a TTS error. If a response emits done: true, Rapida closes the provider connection. If a rule emits neither audio, non-empty error, nor done: true, the response is ignored.

Binary audio response example

Use this when the provider streams raw audio as binary WebSocket frames.

JSON base64 audio response example

Use $decode when the provider returns base64-encoded audio inside JSON.

DSL operators

Every DSL operator is a JSON object with one operator key. Operator objects must contain only the operator and its required fields.

$var

Reads a supported query variable inside speak.query_params.
Rules:
  • $var must be a non-empty string.
  • The operator object must contain only $var.
  • $var is not supported in request rules or response rules. Use $path there.
  • text is not supported as a query variable.

$path

Reads a dot-separated path from the current request scope or JSON response frame.
Rules:
  • $path must be a non-empty string.
  • The operator object must contain only $path.
  • Dot-separated object keys are traversed by key.
  • Arrays are traversed by numeric index, such as chunks.0.audio.
  • Keys that contain a literal dot are not addressable.
  • Missing paths in when.path cause the rule not to match.
  • Missing paths in send.body or emit cause an error.
  • Response rules can use $path only when the current frame is json.

$cast

Casts a rendered value to another type.
Rules:
  • $cast must be string, number, or boolean.
  • The operator object must contain only $cast and value.
  • value can be a literal or another DSL expression.
Cast behavior:

$frame

Reads the full current binary response frame.
Rules:
  • $frame must be binary.
  • The operator object must contain only $frame.
  • $frame is useful when the provider streams raw audio as binary WebSocket frames.
  • $frame: "text" and $frame: "json" are not supported for Custom TTS.

$decode

Decodes a base64 string into bytes.
Rules:
  • $decode must be base64.
  • The operator object must contain only $decode and value.
  • value must resolve to a base64 string.
  • Use $decode when a JSON response contains base64 audio that should become a playable audio chunk.

Unsupported operators and expressions

The following are not supported in Custom TTS:
  • $frame: "text"
  • $frame: "json"
  • $decode formats other than base64
  • Text response frames
  • Regex, contains, starts-with, greater-than, less-than, and compound conditions
  • String interpolation or concatenation
  • Fallback values inside expressions
  • Dynamic headers
  • Dynamic URL path segments
  • Environment variable reads
  • JavaScript or function calls

Complete setup example

Credential:
Audio settings:
Query parameters:
Request rules:
Response rules:

Runtime behavior

  • Rapida builds the final WebSocket URL from baseUrl and speak.query_params.
  • Rapida sends static headers from the credential during the WebSocket handshake.
  • Rapida opens a connection per active message or context. A new context closes the previous connection.
  • text packets open the WebSocket connection if needed.
  • done and interrupt request rules are optional. If no rule exists for that packet, nothing is sent.
  • On interruption, Rapida sends the optional interrupt rule first, then closes the WebSocket connection.
  • Provider audio is interpreted as speak.audio.encoding and speak.audio.sample_rate, then resampled internally when needed.
  • If no response rule matches a provider response, the response is ignored.
  • If a response emits non-empty error, Rapida emits a TTS error.
  • If a response emits audio, Rapida emits a TTS audio packet.
  • If a response emits done: true, Rapida closes the connection and emits a TTS end packet.
  • If the provider closes the WebSocket normally after synthesis has started, Rapida treats that as completion.

Validation checklist

Before saving or testing, confirm the following:
  • apiCompatibility is websocket_v1 or omitted.
  • baseUrl is present and points to the correct WebSocket endpoint.
  • headers include required provider authentication.
  • speak.audio.encoding matches the provider response audio.
  • speak.audio.sample_rate matches the provider response audio.
  • speak.request_rules is valid JSON and contains at least one text rule.
  • speak.response_rules is valid JSON and contains at least one matching audio, done, or error rule.
  • Binary audio providers use { "$frame": "binary" }.
  • JSON base64 audio providers use { "$decode": "base64", "value": ... }.
  • Providers that require finalization have a done request rule.
  • Providers that require cancellation have an interrupt request rule.

Troubleshooting

Text-to-Speech

Configure standard TTS providers and speech delivery.

Speak configuration

See how TTS fits into assistant voice output settings.

Custom STT

Configure a custom speech-to-text provider with the related DSL pattern.

Assistant API Custom TTS

Review runtime behavior for self-hosted assistant-api deployments.