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_KEYEndpoint
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:
| Shape | Example | Result |
|---|---|---|
| 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:
| Block | Fields | Notes |
|---|---|---|
text | text (string, required) | Plain text to check. |
image_url | image_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:
| Field | Meaning |
|---|---|
flagged | true when the model considers the input harmful in at least one category. |
categories | Per-category boolean verdict. |
category_scores | Per-category confidence, 0–1. Use these to set your own thresholds when the boolean verdict is too coarse. |
category_applied_input_types | Which 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_urlblock. - 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:
| Code | When |
|---|---|
20003 | input missing, empty, malformed, over the item / word limit, an image_url.url that is not a public http(s) URL, or stream not false. |
20004 | model missing or not omni-moderation-latest. |
30001 | Insufficient credits for the submitted unit count. |
80001 | Provider rejected the submission (rate limit, upstream balance, transient failure). Refunded. |
80007 | Provider 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_scoresas the tunable signal:flaggeduses 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.
Related
- AI Text Detector — score text for AI authorship.
- AI Humanizer — rewrite AI text to read human.