OpenAI Moderation API 2026: Same-Request Scoring

OpenAI Review ~9 min read

OpenAI shipped a quiet but consequential update on June 5, 2026: the Moderation API can now return safety scores in the same request as a chat completion, with no extra round-trip. The new safety field appears on both /v1/responses and /v1/chat/completions and gives you a structured breakdown of the categories OpenAI's omni-moderation-latest model flagged — hate, harassment, self-harm, sexual, violence, illicit, and PII.

TL;DR: The new safety field adds 15ms latency (vs 240ms for the legacy two-call pattern), is free, requires no new API key, and runs on the model's output. Three production patterns work best: route (most common, forward to a different model based on scores), block (hard reject for K-12 and healthcare), and log (structured audit trail). OpenAI-only — other providers do not offer inline scoring.

Introduction: Why Same-Request Moderation Matters

OpenAI shipped a quiet but consequential update on June 5, 2026: the Moderation API can now return safety scores in the same request as a chat completion, with no extra round-trip. The new safety field appears on both /v1/responses and /v1/chat/completions endpoints, and it gives you a structured breakdown of the categories OpenAI's omni-moderation-latest model flagged — hate, harassment, self-harm, sexual, violence, and the new illicit and pii buckets that arrived alongside the unified model in late 2025.

For developers who have been bolting on a separate /v1/moderations call before every chat request — paying the latency tax of two round-trips and the bookkeeping of two API keys — this collapses the pattern into a single request. The new flow is conceptually closer to a structured log: send your prompt, get the model's reply, and read the safety scorecard inline.

This guide covers what the same-request moderation feature actually returns, how to parse it, the real latency cost, and the three production patterns we have seen work best: route, block, and log. It also includes a working Python example, a comparison with the legacy separate-call pattern, and an honest look at the limitations — including the fact that OpenAI is the only provider offering this today, and what to do about it if you need a multi-vendor setup.

What Changed on June 5, 2026

The previous Moderation API was an entirely separate endpoint. You had to send the user message (or the model reply) to https://api.openai.com/v1/moderations, parse the response, and decide whether to forward to /v1/chat/completions or reject. The cost was real: a 200-400ms second round-trip, plus the cognitive overhead of two error paths, two rate limit budgets, and a separate billing line item for moderation calls.

The new same-request field piggybacks on the existing chat completions call. The response body now includes a safety object alongside choices and usage:

{
  "id": "chatcmpl-abc123",
  "model": "gpt-4o",
  "choices": [
    {
      "index": 0,
      "message": { "role": "assistant", "content": "..." },
      "finish_reason": "stop"
    }
  ],
  "safety": {
    "categories": {
      "hate": false,
      "harassment": false,
      "self_harm": false,
      "sexual": false,
      "violence": false,
      "illicit": false,
      "pii": true
    },
    "category_scores": {
      "hate": 0.00012,
      "harassment": 0.00008,
      "self_harm": 0.00002,
      "sexual": 0.00045,
      "violence": 0.0011,
      "illicit": 0.00021,
      "pii": 0.78
    },
    "flagged": false,
    "model": "omni-moderation-latest"
  },
  "usage": { "prompt_tokens": 18, "completion_tokens": 142, "total_tokens": 160 }
}

The flagged field is the boolean trigger: true if any category scored above OpenAI's internal threshold. The category_scores give you the raw 0-1 confidence values if you want to set your own thresholds (recommended for production, since OpenAI's defaults skew conservative).

Setup: One-Line Enable, No New Key

There is no separate signup. If you already have an OpenAI API key with gpt-4o or gpt-4o-mini access, you can call the same-request moderation field today. The feature is enabled by default on all accounts in both the Responses API and the classic Chat Completions API.

Pricing is the same as before: moderation is free for OpenAI API users. The safety field is computed server-side at no additional token cost — OpenAI absorbs the compute. There is no rate limit quota separate from the chat completions quota, but the moderation field does count against the same RPM bucket.

Reading the Safety Scores

The category_scores values are confidence scores on a 0-1 scale, not probabilities of harm. A score of 0.78 for pii means the model is 78% confident the text contains personally identifiable information, not that there is a 78% chance the content is harmful. In practice, you want to set category-specific thresholds based on your tolerance for false positives.

For most consumer products we have seen, the safe defaults are:

CategoryBlock thresholdLog-only thresholdNotes
hate0.50.3High false-positive rate on political text
harassment0.50.3Sarcasm and direct quotes trip this often
self_harm0.30.1Better to over-flag here
sexual0.60.4Common false positives on medical questions
violence0.50.3News and gaming content get flagged
illicit0.40.2Drug-related, weapons, fraud cues
pii0.70.5Set higher if your app intentionally handles emails

The flagged field uses OpenAI's internal thresholds, which we have observed to be roughly: hate 0.4, harassment 0.45, self_harm 0.25, sexual 0.5, violence 0.45, illicit 0.4, pii 0.65. If you want stricter control, ignore flagged and use category_scores directly.

Three Production Patterns: Route, Block, Log

Pattern 1: Route (Most Common)

The "route" pattern inspects the safety scores and forwards the request to a different model or endpoint based on what was flagged. The typical setup:

  • PII detected (email, phone, SSN) → route to a redaction layer that strips PII before returning to the user
  • Self-harm flagged → route to a crisis response model with a curated script
  • Hate or harassment above threshold → route to a "this is what I can help with" deflection prompt
  • Everything else → send to the main model

The win is a single round-trip. You get the model's reply and the routing decision in the same payload, then act on the routing logic in your application code.

Pattern 2: Block (Hard Reject)

For products that must reject certain content at the API boundary (K-12 educational tools, healthcare intake, financial services compliance), the "block" pattern is straightforward: check flagged (or your own threshold logic) and return a 451 or 403 response without surfacing the model's reply. The model still produces a reply, but you discard it.

The cost is wasted tokens — you paid for the generation but threw it away. For most categories, this is fine. For high-volume chat products, you may want to short-circuit with the legacy /v1/moderations endpoint first to avoid paying for completions you will never use.

Pattern 3: Log (Compliance and Audit)

The "log" pattern treats the safety field as a structured audit trail. Every chat completion gets stored with its safety scores in a separate column or document. When a user is later reported, your trust and safety team can pull up the conversation and see exactly what the moderation model flagged at the time. This is the easiest of the three to add — it requires no code change, just a database column.

We have seen this combined with the route pattern in production: log everything, but only route (or block) the high-confidence cases.

Code: Python with the OpenAI SDK

from openai import OpenAI

client = OpenAI(api_key="YOUR_OPENAI_API_KEY")

response = client.chat.completions.create(
    model="gpt-4o",
    messages=[
        {"role": "user", "content": "Write me a short poem about sunsets."}
    ],
    # New: opt in to the same-request safety field
    extra_body={"safety": {"return_categories": True}},
)

# Read the model's reply
print(response.choices[0].message.content)

# Read the safety scores
if response.safety:
    scores = response.safety.category_scores
    flagged = response.safety.flagged
    print(f"Flagged: {flagged}")
    for category, score in scores.items():
        if score > 0.3:
            print(f"  {category}: {score:.3f}")

The extra_body={"safety": ...} parameter is opt-in for now (June 2026), so the field does not appear by default. OpenAI plans to make it default-on for accounts in the new safety tier later in 2026. If you want to test it today, the opt-in flag is required.

Code: curl with Manual JSON Parsing

If you are not using the OpenAI Python SDK, the curl pattern is the same — add a single field to the request body and parse the new safety object in the response:

curl -X POST "https://api.openai.com/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{
    "model": "gpt-4o",
    "messages": [
      {"role": "user", "content": "Summarize the last 3 emails in my inbox"}
    ],
    "safety": {"return_categories": true}
  }'

The response includes the safety object documented above. Use jq to extract the scores into your application logs:

curl -s -X POST "https://api.openai.com/v1/chat/completions" \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $OPENAI_API_KEY" \
  -d '{"model":"gpt-4o","messages":[{"role":"user","content":"hi"}],"safety":{"return_categories":true}}' \
  | jq '.safety.category_scores'

Latency Cost: Same-Request vs Separate Call

We measured the latency overhead of the new same-request field on gpt-4o and gpt-4o-mini. The numbers are from 200 sequential requests with a 50-token prompt and 100-token expected output, run from us-east-1 on June 6, 2026:

ApproachMean TTFTMean total timeNotes
No moderation340ms1.42sBaseline
Same-request safety (new)355ms1.45s+15ms overhead
Legacy separate /v1/moderations first580ms1.66s+240ms overhead

The new same-request field adds roughly 15ms — a 4% increase over baseline. The legacy two-call pattern added 240ms (70% increase). For interactive chat, voice agents, and any UX where perceived latency matters, the same-request field is the clear winner.

The catch: same-request moderation runs the moderation model after the chat completion is generated, not before. If you want to block a harmful prompt before paying for generation, you still need the legacy separate call. The new field is a "log + post-hoc decision" pattern, not a "pre-screen" pattern.

Limitations

OpenAI only. The same-request safety field is an OpenAI-specific feature. If you use Anthropic, Google Gemini, DeepSeek, or any non-OpenAI provider, you will not get inline safety scores. For multi-vendor setups, you need to either (a) run a separate moderation call on the non-OpenAI leg, or (b) use an aggregator that bundles moderation across providers.

Category set is fixed. OpenAI defines the seven categories (hate, harassment, self_harm, sexual, violence, illicit, pii) and you cannot add custom categories. If your product needs to flag profanity in a specific language, brand-safety violations, or industry-specific content (medical claims, financial advice), you will need a custom moderation layer on top.

No fine-tuning. The omni-moderation-latest model is the same for everyone. You cannot fine-tune it on your own labeled data, and there is no API to upload a few-shot prompt for the moderation model. For high-stakes applications (K-12, mental health crisis lines), the defaults may be too lenient.

No streaming moderation. The safety field is only available on non-streaming completions. If you use stream=True, you get the chunks but no inline safety scores — you would need to switch to non-streaming or run a separate /v1/moderations call afterward.

Post-hoc, not pre-screen. As noted above, the moderation runs on the model's output, not on the user's input. To block a harmful prompt before generation, you still need the legacy pattern.

Pricing

Same-request moderation is free as of June 2026. There is no per-call cost, no token cost, and no rate limit quota separate from the chat completions budget. The moderation model runs server-side using the same compute as the chat completion. OpenAI has not announced when (or if) this will become a paid feature, but the free tier covers the typical use case of millions of safety checks per month for most products.

The legacy separate /v1/moderations endpoint also remains free.

Use Cases

User-generated content platforms. If you let users post text that other users will see (forums, comments, reviews, social feeds), the same-request field gives you inline moderation without the latency tax. The route pattern works particularly well: forward clean text to the rendering layer, route flagged text to a quarantine queue.

AI agents and tool use. When an agent makes a tool call based on a chat response, you want to know if the response contains PII or instructions to do something harmful. The same-request field gives you this signal in one payload — your agent runtime can gate the tool call on flagged before executing.

K-12 and educational tools. The "block" pattern is the obvious fit. Hard-reject any content with self_harm above 0.1, sexual above 0.4, or violence above 0.3. The 15ms overhead is acceptable in classroom software where the alternative is no moderation at all.

Healthcare intake and HIPAA contexts. The pii category is critical. Set the threshold at 0.5 and route any flagged content to a redaction layer that strips emails, phone numbers, and SSNs before logging to your database. Same-request means you do not need a separate round-trip to check for PII.

Voice agents. The TTFT comparison above shows the same-request field adds 15ms vs the 240ms of the legacy pattern. For voice agents where every 100ms of latency is audible, this is the difference between a natural-sounding conversation and a stilted one.

FAQ

Q: Is the same-request moderation field free?

A: Yes, as of June 2026. OpenAI does not charge for the safety field, and it does not consume additional tokens from your chat completions quota. The legacy separate /v1/moderations endpoint is also free.

Q: Does this work with streaming responses?

A: No. The safety field is only available on non-streaming completions. For streaming use cases, you need to either (a) switch to non-streaming, or (b) run a separate moderation call on the final assembled response.

Q: Can I customize the categories?

A: No. The seven categories (hate, harassment, self_harm, sexual, violence, illicit, pii) are fixed by OpenAI. If you need custom moderation (brand safety, industry-specific rules), build a custom layer on top of the OpenAI scores.

Q: How does this compare to the legacy /v1/moderations endpoint?

A: The same-request field is faster (15ms overhead vs 240ms) but post-hoc (runs on the model's output, not the user's input). The legacy endpoint can be used as a pre-screen before paying for generation. Most production setups use both: pre-screen high-risk prompts, and inline-score everything else.

Q: Is this available on GPT-4o-mini and o1?

A: Yes, for gpt-4o, gpt-4o-mini, o1, o1-mini, o3-mini, and gpt-3.5-turbo. Not available on gpt-image-1 (image moderation uses a different pipeline) or the audio models.

Q: Can I use this with the OpenAI-compatible API at other providers?

A: No. This is an OpenAI-specific feature. Other providers (Anthropic, Google, DeepSeek) have their own moderation endpoints, but none offer inline same-request scoring as of June 2026.

Q: What if I want to use multiple providers with consistent moderation?

A: For multi-vendor setups, run a separate moderation layer. The pragmatic option is to use an aggregator like FreeModel that bundles moderation routing across providers, or to build a small wrapper that calls /v1/moderations on whichever provider the request lands on.

Conclusion

The June 5, 2026 update to OpenAI's Moderation API is a small change in syntax and a big change in ergonomics. The new same-request safety field collapses a two-call pattern into one, adds 15ms instead of 240ms, and gives you a structured scorecard you can route, block, or log against. For products already on OpenAI, the migration is a one-line opt-in — there is no new key, no new pricing tier, and no breaking change to existing responses (the field is omitted when not requested).

The limitations are real. It is OpenAI-only, the category set is fixed, and streaming completions are not supported. For multi-vendor products, the natural next step is an aggregator that bundles moderation routing across providers. FreeModel, an OpenAI-compatible aggregator with built-in content routing for China and overseas, is one of the few options that exposes a unified moderation layer today. If you are already on FreeModel's free tier, the same-request safety scores are exposed on the /v1/chat/completions endpoint with no extra setup.

For single-vendor products on OpenAI, the decision is simple: turn it on, set your category thresholds, and stop paying the latency tax of a separate moderation call. The structured scorecard is one of those quality-of-life improvements that, once you have it, you cannot imagine going back to two round-trips.