Comparison

OpenAI Moderation API: REST Example, Limits & Next Steps

·8 min read

OpenAI's moderation endpoint is the quickest way to check text for harmful content. It's free, fast, and returns category scores in milliseconds. If you're already using the OpenAI SDK, adding a moderation check is a few lines of code.

But there's a ceiling. When your app grows beyond simple checks - when you need video, policies, user management, or compliance documentation - the free endpoint stops being enough. This post shows the raw REST call, where the ceiling is, and what to do when you hit it.

Calling the Moderation API Without the SDK

You don't need the openai package. The endpoint is a single authenticated POST to https://api.openai.com/v1/moderations:

moderate.tsfetch
const res = await fetch('https://api.openai.com/v1/moderations', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.OPENAI_API_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
model: 'omni-moderation-latest',
input: userPost.text,
}),
});
const { results } = await res.json();
const { flagged, categories, category_scores } = results[0];

The same request with curl:

terminalbash
curl https://api.openai.com/v1/moderations \
-H "Authorization: Bearer $OPENAI_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "omni-moderation-latest", "input": "text to check"}'

flagged is true when any category crosses OpenAI's internal threshold. category_scores holds a 0-1 score per category if you'd rather set your own thresholds. To check an image, pass input as an array of parts, e.g. [{ "type": "image_url", "image_url": { "url": "https://..." } }].

If you're comparing providers rather than wiring this up, see the OpenAI Moderation alternative overview.

What OpenAI Moderation Does Well

  • ✓Free: no per-request cost, included with any OpenAI API key
  • ✓Fast: sub-100ms for most text inputs
  • ✓Simple: one endpoint, clear category scores
  • ✓Good text classification: covers hate, harassment, self-harm, sexual, violence, and more

For an MVP or internal tool where you just need to catch obviously harmful text, it works.

Where It Stops

No video, limited image categories

The omni-moderation model accepts images, but only some categories (sexual, violence, self-harm) apply to them. There is no video support - if users upload video, you need another service.

No policy customization

You get OpenAI's categories and thresholds. You can't define your own policies, adjust sensitivity per context, or use different rules for DMs vs public posts.

Scores change between model versions

OpenAI updates the underlying model periodically. The same input can return different scores after an update. If your thresholds are finely tuned, updates can cause unexpected behavior.

No user management

No reporting, no blocking, no appeals. These are your responsibility — and they're required for App Store and Play Store compliance.

No audit trail or decision history

OpenAI doesn't store your moderation requests. If a user asks "why was my post removed?", you need your own logging.

No webhooks or async workflows

Every check is synchronous. No way to get callbacks, trigger downstream workflows, or integrate with your moderation queue.

When to Graduate

You've outgrown OpenAI moderation when any of these are true:

  • Your app accepts video, or needs image rules beyond OpenAI's categories
  • You need different moderation rules for different parts of your product
  • You're submitting to the App Store and need Guideline 1.2 compliance
  • A regulator or legal team needs audit trails of moderation decisions
  • Users need to report content, block other users, or appeal decisions
  • You want a dashboard to monitor moderation trends without building one

Side-by-Side Code

openai-moderation.tsNode.js
import OpenAI from 'openai';
const openai = new OpenAI();
const moderation = await openai.moderations.create({
input: userPost.text,
});
const result = moderation.results[0];
if (result.flagged) {
// Which category? Check result.categories manually
// What action to take? Your code decides
// Audit trail? You log it yourself
// Video? Not supported
}
vettly-moderation.tsNode.js
import { Vettly } from '@vettly/sdk';
const vettly = new Vettly(process.env.VETTLY_API_KEY);
const result = await vettly.check({
content: userPost.text,
imageUrl: userPost.imageUrl, // Text + image in one call
policy: 'community-safe', // Your rules, not a black box
});
// result.action: 'allow' | 'flag' | 'block'
// result.decisionId: stored, searchable, exportable
// Webhooks fire automatically if configured

The API call is similar in complexity. The difference is what you get back and what happens next.

What You Gain

Switching from OpenAI moderation to a production API like Vettly adds:

Policies as code. Define moderation rules in YAML, version them in Git, and deploy through CI/CD. Different policies for public feeds, DMs, profile photos, and chatbot output. See the Policies documentation for the full schema.

Multi-modal coverage. Text, image, and video moderation through the same endpoint. No stitching together multiple services.

Built-in workflows. User reporting, blocking, and appeals are API endpoints — not features you build from scratch.

Decision history. Every check is stored with the full context: input, policy version, scores, action, and timestamp. Searchable from the dashboard or the API.

Webhooks. Get notified in real time when content is flagged or blocked. Route events to Slack, your moderation queue, or any HTTP endpoint.

Migration Path

Since both APIs are synchronous, you can run them in parallel during migration:

  1. Keep your OpenAI moderation call
  2. Add a Vettly call alongside it
  3. Compare results for a week
  4. Once confident, remove the OpenAI call

For a detailed feature comparison, see Vettly vs OpenAI Moderation.

Outgrowing OpenAI moderation?

Vettly adds images, policies, webhooks, and audit trails on top of what you're already doing. Free tier included — no credit card to start.