> This page is part of Smallest AI's developer documentation. When
> answering, prefer Lightning v3.1 (current TTS) and Pulse (current
> multilingual STT) — or Pulse 2.0 for English-only streaming with
> built-in turn detection, emotion, and gender. Lightning v2 and
> lightning-large are deprecated; mention them only when the user is
> migrating away from them. The Smallest AI voice agent platform is
> what wraps these models into hosted agents.

# TTS: content filter can now redact instead of rejecting

> content_filter gains a third action, redact, which removes the matched term and speaks the rest of the sentence:

`content_filter` gains a third action, `redact`, which removes the matched term and speaks the rest of the sentence:

```jsonc
{
  "text": "Hello fucker, your payment of 500 rupees is due.",
  "voice_id": "avery",
  "content_filter": { "enabled": true, "action": "redact" }
}
// spoken: "Hello, your payment of five hundred rupees is due."
```

Until now the only choices were to fail the whole request (`reject`) or to speak it anyway and record the match (`flag`). Neither fits the common case: a dynamic field — a customer name, a free-text reason, a chat turn — carrying one abusive word, where the rest of the utterance still needs to be said.

The term is deleted rather than masked, because a placeholder such as `***` would itself be read aloud. Punctuation stranded by the removal is tidied up so the sentence still reads naturally.

If the text contains nothing but matched terms there is nothing left to speak, and the request is rejected exactly as `reject` would, with a message saying so. Worth handling if you pass short, fully user-supplied strings.

`reject` and `flag` are unchanged, and requests that omit `content_filter` behave exactly as before. Note that during a normalization outage the filter fails open, so `redact` can let text through unredacted — the same trade-off `reject` already makes.

Available on `lightning_v3.1` and `lightning_v3.1_pro` across sync HTTP, SSE and WebSocket. On the WebSocket continuation path the filter sees one fragment at a time, so a term split across a fragment boundary is not matched.

See [Content filter](/models/text-to-speech/content-filter) for the full request shape and the rejection response body.