> ## Documentation Index
> Fetch the complete documentation index at: https://docs.flex.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Moderation

> Screen text and images with a safety classifier via `POST /v1/moderations`.

A moderation model reads a request and tells you whether it is safe to act on, before you spend tokens or GPU time generating anything. `POST /v1/moderations` takes OpenAI's request shape and returns one verdict per input, with the model's own hazard categories.

The moderation model is `Llama-Guard-4-12B`. Moderation models answer on this endpoint only, so call them here rather than through `/v1/chat/completions`.

## Example

```bash cURL theme={null}
curl https://api.flex.ai/v1/moderations \
  -H "Authorization: Bearer $FLEXAI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "Llama-Guard-4-12B",
    "input": "How do I hotwire a car that is not mine?"
  }'
```

```python Python theme={null}
import os
import requests

resp = requests.post(
    "https://api.flex.ai/v1/moderations",
    headers={"Authorization": f"Bearer {os.environ['FLEXAI_API_KEY']}"},
    json={"model": "Llama-Guard-4-12B", "input": "How do I hotwire a car that is not mine?"},
)
resp.raise_for_status()

result = resp.json()["results"][0]
flagged_codes = [code for code, hit in result["categories"].items() if hit]
print(result["flagged"], flagged_codes)
```

```typescript TypeScript theme={null}
const resp = await fetch("https://api.flex.ai/v1/moderations", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.FLEXAI_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "Llama-Guard-4-12B",
    input: "How do I hotwire a car that is not mine?",
  }),
});

const [result] = (await resp.json()).results;
const flaggedCodes = Object.entries(result.categories)
  .filter(([, hit]) => hit)
  .map(([code]) => code);
console.log(result.flagged, flaggedCodes);
```

The responses are read as plain JSON rather than through an OpenAI SDK type, because `categories` carries the model's own codes rather than OpenAI's category names.

## Inputs

`model` is required. `input` takes one of three forms:

* **A string.** You get one result.
* **A list of strings, up to 32.** You get one result per string, in the same order.
* **A list of content parts, judged together as one item.** Use text parts, `{ "type": "text", "text": "..." }`, and at most one image part, `{ "type": "image_url", "image_url": { "url": "..." } }`. You get one result.

A list holds either strings or content parts, not a mix of the two.

```json theme={null}
{
  "model": "Llama-Guard-4-12B",
  "input": [
    { "type": "text", "text": "Is this image safe to post?" },
    { "type": "image_url", "image_url": { "url": "https://example.com/photo.jpg" } }
  ]
}
```

## Response

```json theme={null}
{
  "id": "modr-4f1c...",
  "model": "Llama-Guard-4-12B",
  "results": [
    {
      "flagged": false,
      "categories": {
        "S1": false, "S2": false, "S3": false, "S4": false, "S5": false,
        "S6": false, "S7": false, "S8": false, "S9": false, "S10": false,
        "S11": false, "S12": false, "S13": false, "S14": false
      }
    }
  ]
}
```

`flagged` is `true` when the model judges the input unsafe, and `categories` names the hazards it identified. Every code is present on every result, `true` or `false`. There is no `category_scores`: Llama Guard 4 returns a verdict, not a score.

Decide on `flagged`. The model can judge an input unsafe without naming a category it recognizes, so a flagged result can have every category `false`.

| Code | Category |
| - | - |
| `S1` | Violent Crimes |
| `S2` | Non-Violent Crimes |
| `S3` | Sex Crimes |
| `S4` | Child Exploitation |
| `S5` | Defamation |
| `S6` | Specialized Advice |
| `S7` | Privacy |
| `S8` | Intellectual Property |
| `S9` | Indiscriminate Weapons |
| `S10` | Hate |
| `S11` | Self-Harm |
| `S12` | Sexual Content |
| `S13` | Elections |
| `S14` | Code Interpreter Abuse |

When the input includes an image, the model checks `S1` to `S13`, so `S14` is always `false` for that result.

## What to plan for

* **A batch succeeds or fails as a whole.** If any item fails, the request returns one error rather than partial results, so every result stays aligned with its input. Items that had already completed were real calls and are still billed.
* **Each item counts toward your rate limit.** A list of 10 strings uses 10 requests from your key's per-minute limit.
* **An unreadable verdict is an error, never a silent pass.** If the model's reply can't be read as a verdict, you get a `502` rather than `flagged: false`.
* **Only moderation models answer here.** Any other model returns `400` with `code: "model_not_supported"`, and the message lists the models that do.

## Billing

Each input item is one call to the moderation model, billed on its tokens at the model's input and output rates. A list of three strings is three calls. Rates are on [the model page](https://flex.ai/models/llama-guard-4-12b) and in `GET /v1/models`.

## See also

* [Model discovery](https://docs.flex.ai/inference-api/guides/model-discovery.md) — moderation models have `category: "moderation"`.
* [Video generation](https://docs.flex.ai/inference-api/guides/video.md) — screen the prompt you actually send to a generator, not only the one the user typed.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.