Seedance 2.5 is live — 30-second cinematic video with native audio & real-person references
rreAPI Docs

omni-moderation-latest

Moderate text, images, or mixed input with omni-moderation-latest — one async task returns a flagged verdict, 13 category scores, and which input type triggered each. Billed per moderation unit.

omni-moderation-latest is a single async endpoint that checks text, images, or a mix of both against 13 harm categories and returns a flagged verdict with per-category scores. See current pricing on the model page.

Quick example

curl https://reapi.ai/api/v1/moderations \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "omni-moderation-latest",
    "input": [
      { "type": "text", "text": "Is this comment safe to publish?" },
      { "type": "image_url", "image_url": { "url": "https://example.com/photo.jpg" } }
    ]
  }'
import requests

resp = requests.post(
    "https://reapi.ai/api/v1/moderations",
    headers={
        "Authorization": "Bearer YOUR_API_KEY",
        "Content-Type": "application/json",
    },
    json={
        "model": "omni-moderation-latest",
        "input": [
            {"type": "text", "text": "Is this comment safe to publish?"},
            {"type": "image_url", "image_url": {"url": "https://example.com/photo.jpg"}},
        ],
    },
    timeout=30,
)
print(resp.json())
const r = await fetch("https://reapi.ai/api/v1/moderations", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    model: "omni-moderation-latest",
    input: [
      { type: "text", text: "Is this comment safe to publish?" },
      { type: "image_url", image_url: { url: "https://example.com/photo.jpg" } },
    ],
  }),
});
console.log(await r.json());
package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io"
    "net/http"
)

func main() {
    body, _ := json.Marshal(map[string]any{
        "model": "omni-moderation-latest",
        "input": []map[string]any{
            {"type": "text", "text": "Is this comment safe to publish?"},
            {"type": "image_url", "image_url": map[string]string{"url": "https://example.com/photo.jpg"}},
        },
    })
    req, _ := http.NewRequest("POST",
        "https://reapi.ai/api/v1/moderations", bytes.NewReader(body))
    req.Header.Set("Authorization", "Bearer YOUR_API_KEY")
    req.Header.Set("Content-Type", "application/json")

    resp, _ := http.DefaultClient.Do(req)
    defer resp.Body.Close()
    out, _ := io.ReadAll(resp.Body)
    fmt.Println(string(out))
}

Submit response

{
  "id": "task_01a04de4f56c77f387b030319362ff46",
  "model": "omni-moderation-latest",
  "status": "processing",
  "created_at": 1788013250
}

Poll GET /api/v1/tasks/{id} until status === "completed". A check usually finishes within a few seconds.


Authentication

Every call needs a Bearer token. Generate keys at reapi.ai/settings/apikeys.

Authorization: Bearer YOUR_API_KEY

Endpoint

POST /api/v1/moderations
GET  /api/v1/tasks/{id}

Submission is async. The POST returns immediately with a task id; polling the task endpoint returns the same envelope until completion. Polling does not consume credits.


Request body

model — required

Always "omni-moderation-latest".

input — required

The content to moderate. Three shapes are accepted:

ShapeExampleResult
Single string"I want to kill someone"One entry in results
Array of strings["hello", "I hate you"]One entry per string
Array of content blocks[{ "type": "text", "text": "…" }, { "type": "image_url", "image_url": { "url": "https://…" } }]One entry for the whole set

Content blocks:

BlockFieldsNotes
texttext (string, required)Plain text to check.
image_urlimage_url.url (string, required)A public http(s) URL. Base64 / data: URIs are rejected — reAPI media inputs are URL-only across every model.

Strings and text blocks must be non-empty; arrays must have at least one item.

Limits: up to 500 items per request and 30,000 words (300,000 characters) of text in total, summed across every string / text block. Split larger jobs across requests.

stream — optional (boolean)

Only false is supported. Omit it (the default) or send false; any other value is rejected with 20003. The task contract already delivers the whole verdict in one poll response, so there is nothing to stream.


Output

{
  "id": "task_01a04de4f56c77f387b030319362ff46",
  "model": "omni-moderation-latest",
  "status": "completed",
  "created_at": 1788013250,
  "output": {
    "moderation": {
      "results": [
        {
          "flagged": true,
          "categories": {
            "harassment": true,
            "harassment/threatening": false,
            "hate": false,
            "hate/threatening": false,
            "illicit": false,
            "illicit/violent": false,
            "self-harm": false,
            "self-harm/instructions": false,
            "self-harm/intent": false,
            "sexual": false,
            "sexual/minors": false,
            "violence": false,
            "violence/graphic": false
          },
          "category_scores": {
            "harassment": 0.8869,
            "harassment/threatening": 0.0384,
            "hate": 0.0001,
            "hate/threatening": 0.0000,
            "illicit": 0.0000,
            "illicit/violent": 0.0000,
            "self-harm": 0.0005,
            "self-harm/instructions": 0.0000,
            "self-harm/intent": 0.0001,
            "sexual": 0.0000,
            "sexual/minors": 0.0000,
            "violence": 0.0322,
            "violence/graphic": 0.0000
          },
          "category_applied_input_types": {
            "harassment": ["text"],
            "harassment/threatening": ["text"],
            "hate": ["text"],
            "hate/threatening": ["text"],
            "illicit": ["text"],
            "illicit/violent": ["text"],
            "self-harm": ["text", "image"],
            "self-harm/instructions": ["text", "image"],
            "self-harm/intent": ["text", "image"],
            "sexual": ["text", "image"],
            "sexual/minors": ["text"],
            "violence": ["text", "image"],
            "violence/graphic": ["text", "image"]
          }
        }
      ]
    }
  },
  "usage": { "credits": 1 },
  "error": null
}

Reading a result

output.moderation.results[] holds one entry per input item (one per string for an array of strings; a single entry for a content-block array). Each entry:

FieldMeaning
flaggedtrue when the model considers the input harmful in at least one category.
categoriesPer-category boolean verdict.
category_scoresPer-category confidence, 01. Use these to set your own thresholds when the boolean verdict is too coarse.
category_applied_input_typesWhich input types (text, image) each category was evaluated against for this request. Image checks cover the self-harm, sexual, violence and violence/graphic families; the remaining categories are text-only.

The 13 categories: harassment, harassment/threatening, hate, hate/threatening, illicit, illicit/violent, self-harm, self-harm/instructions, self-harm/intent, sexual, sexual/minors, violence, violence/graphic.

The category vocabulary and scores are returned exactly as the model produces them; reAPI does not remap or round them.


Pricing

Billed per moderation unit:

  • Text: one unit per 1,000 words, summed across every text item in the request. Each text item counts as at least 50 words, so a batch of very short strings is not billed as free.
  • Images: one unit per image_url block.
  • Every request bills at least one unit.

Units are converted to credits once per request and rounded up, so a large batch is cheaper per item than many single calls. Polling does not add any charge. Failed requests are refunded automatically.

1 credit = $0.001 USD. See the pricing table on the model page for the current per-unit rate.


Errors

Standard envelope:

{
  "error": {
    "code": 20003,
    "message": "input: input is required",
    "request_id": "req_..."
  }
}

Common cases:

CodeWhen
20003input missing, empty, malformed, over the item / word limit, an image_url.url that is not a public http(s) URL, or stream not false.
20004model missing or not omni-moderation-latest.
30001Insufficient credits for the submitted unit count.
80001Provider rejected the submission (rate limit, upstream balance, transient failure). Refunded.
80007Provider rejected the input as invalid (for example an image URL it could not fetch). Refunded.

Full catalog: /docs/api/errors.


Tips

  • Send an array of strings to screen a batch of comments in one task — you get one verdict per string and a single bill.
  • Pair text and an image in one content-block array when they are published together (a caption plus its photo); the model scores the combination as one item.
  • Treat category_scores as the tunable signal: flagged uses the model's default thresholds, which may be stricter or looser than your policy.
  • Image URLs must be fetchable from the public internet. Signed URLs work as long as they are valid when the task runs.

Table of Contents