Four places a request can be screened
A prompt on its way to a model can now meet screening at four layers, and your gateway controls only one of them.
- Your own layer: application code and gateway policy, such as pattern checks or a classifier you run before the call.
- An intermediary: a hosted router or aggregator between you and the model. OpenRouter announced on 27 October 2026 that it will screen all inference requests for child sexual abuse material (CSAM) as they pass through, in flight, during request processing.1
- The provider's policy layer: account, key or team blocks, and any automated safety checks the provider runs under its own terms.
- The model itself: behavior shaped by the provider's defaults and, increasingly, by parameters you send.
The xAI change sits at layer 4. A guidelines array on the request sets how Grok handles named content categories; today the categories are nsfw, violence and profanity, and the only behavior is decline. Categories you leave out keep the model's default moderation.2
This article does not repeat how to build pattern or classifier checks at your own layer; the guardrails article and the payload logging policy cover that. The question here is narrower: what the other three layers do to your traffic, how it surfaces, and what you can show a reviewer.
Who screens what, by layer
| Layer | What it does | Who configures it | Visible to the app as |
|---|---|---|---|
| Gateway or app | Your own checks on prompts and responses | You | An error you define |
| OpenRouter, in flight | Hash comparison against known CSAM, plus review of suspected new material1 | OpenRouter; not optional per its announcement | Not stated in the announcement |
| OpenRouter moderation flag | A provider requested moderation and flagged input3 | Provider and router | An error with reasons, flagged_input, provider_name, model_slug in error.metadata3 |
| xAI guidelines | Model declines chosen categories while writing its answer2 | You, per request | A normal response, same shape2 |
| Provider account policy | Key or team blocked or without permission | Provider | A 403 on xAI4 |
Two rows deserve emphasis. First, OpenRouter's announcement describes what is screened and retained but not the wire format of a flagged request, so a gateway should not hard-code an assumption. Second, the xAI guidelines are not a filter in front of the model. Grok follows them as it writes its response, in its own words.2 That makes them a behavior setting, not a block.
How blocked and flagged requests appear to the app
There are three shapes, and a gateway has to distinguish them because the right reaction differs.
A hard error with detail. OpenRouter documents a 403 for "insufficient permissions, guardrail block, or moderation flag". For a moderation flag, error.metadata carries the reasons, the flagged text segment (capped at 100 characters, truncated in the middle if longer), the provider that requested moderation and the model slug.3 A guardrail block on the same status looks different: a message about the block reason and, for pattern detectors, the matched patterns.3 One status code, several causes, so branching on 403 alone is wrong.
A hard error from your own gateway. INFRO returns 403 with error.code of guardrail_blocked when a guardrail refuses a request, and guardrail_unavailable is a separate code on the same status.5 The type string is stable and meant to be branched on; the message wording can change.5
A soft decline. With xAI guidelines, nothing in the response shape tells you a decline happened.2 The user sees a refusal written in prose. If your product has a "the model refused" metric, it has to be built from text classification or sampling, not from a status code.
A fourth case arrives as a 400: when every provider tried rejected a request as invalid, INFRO returns the provider's own message prefixed Provider rejected the request:, with credential-shaped strings redacted and a 500-character cap.5 Providers can use that channel for policy rejections as well as schema errors, so read the message in logs, but do not parse it in code.
def classify(status: int, body: dict) -> str:
err = body.get("error", {}) if isinstance(body, dict) else {}
meta = err.get("metadata") or {}
code = err.get("code")
if status == 403 and code in ("guardrail_blocked", "guardrail_unavailable"):
return "gateway_policy" # your own gateway layer
if status == 403 and "reasons" in meta and "provider_name" in meta:
return "provider_moderation" # upstream flagged the input
if status == 403:
return "permission_or_other" # key, team, budget, guardrail
if status == 400 and str(err.get("message", "")).startswith("Provider rejected"):
return "provider_rejected" # read the message, do not parse it
return "other"
# Log the class, status, request id and provider name.
# Do NOT log meta["flagged_input"] unless your payload policy allows prompt text.Failure modes a gateway has to design for
Retrying a block as if it were an outage. Failover exists for timeouts and 5xx before the response starts. A content refusal is a decision, not a fault. Sending the same prompt to a second provider after a moderation 403 can look like shopping for a model that will answer, which is a bad pattern to explain to a reviewer. In INFRO, failure rules decide per failure kind whether to retry, move on or stop; test how a provider's 403 and 400 are handled on your routes before relying on it, because this article did not confirm how every provider rejection is classified.
Treating flagged_input as safe to log. It is up to 100 characters of the user's text.3 If your payload logging is off, copying it into an error log reverses that decision.
Assuming retention rules from the marketing name. OpenRouter's announcement says that for content under its Zero Data Retention (ZDR) policy, it does not retain prompts or responses after processing, except when you choose to store them or when retention is needed for CSAM review, reporting and related legal preservation. Screening applies to ZDR traffic too.1 The same page says content flagged as potential CSAM may be retained for human review, including content that does not match a known hash, and that a flag is a suspicion rather than a determination.1
Forgetting the per-request nature of guidelines. xAI guidelines apply only to the request that carries them; for a whole conversation they must be sent on every request. They currently do not work with multi-agent models or deferred completions.2 A gateway or wrapper that adds the array only on the first turn leaves later turns on default moderation.
Reading the provider as the only retainer. OpenRouter notes that model labs and providers may use their own screening and retention methods, and some may retain content to run automated safety checks before anything has been flagged. Those practices are separate from its in-flight screening.1 Its docs add that it has no routing rules that change with providers' retention policies; users can ignore providers that do not meet their requirements.6
What the reporting duty means for your contract review
The OpenRouter announcement states that under US law covered providers must report to the NCMEC CyberTipline as soon as reasonably possible after obtaining actual knowledge of specified apparent offenses, and that reported contents and certain related material must be preserved for one year after submission. It says this applies to reported material, not to every item flagged for review, and that ZDR does not remove the duty.1
For a procurement team the consequence is practical, not legal advice: a "no retention" clause in a vendor agreement is incomplete unless it names this exception. Ask each intermediary and provider two things in writing: whether in-flight screening exists, and what is retained, for how long and by whom when something is flagged. If you route through more than one party, you need the answer per hop.
What to keep for a security or procurement review
Reviewers ask for artifacts, not assurances. Keep these, each dated:
- Dated copies of provider and intermediary terms. Save the retention and screening language as of the day you approved the provider, with the URL and retrieval date. Pages change; the CSAM provisions were announced as documentation and terms updates in progress.1
- A screening map. The table above, filled in for your own routes: which layer screens, which you configure, which are visible to the app.
- Request records with the outcome class. Request id, project, key, model, provider, status, error type and your own class from the classifier above. Metadata only.
- The request configuration that produced behavior. For xAI, the
guidelinesarray in versioned code or config, since the response shape will not show it.2 - Policy change history. Who turned a guardrail on or changed an allowlist, and when.
- A retention register line for each exception. Example: ZDR with the CSAM review exception, quoted from the provider.
What a gateway on your own accounts can and cannot cover
Because INFRO works over provider accounts you already hold, the provider's screening and terms are the ones in your own contract, and you pick them by choosing which connections a route uses. What INFRO adds is at your layer: guardrails check text in chat completion prompts and responses and can block, redact or flag, with a stable 403 guardrail_blocked code, while images and audio inside a message are not inspected, and the docs say detection can miss things.75 Request traces and usage records give the per-request metadata a review needs, with prompt and completion logging off by default and a retention window you choose, and the audit log records policy changes with actor and timestamp. None of this is a CSAM control, and INFRO does not replace a provider's or router's screening.
A checklist before the next vendor review
- Every route has a written screening map: gateway, intermediary, provider, model.
- Your client or gateway branches on error type and metadata, not on 403 alone.
- Moderation 403s are not retried on another provider by default.
flagged_inputand similar fields are excluded from logs unless policy allows.- If you use xAI guidelines, the array is added on every request of a conversation.
- Retention registers name the ZDR exception for flagged content wherever a vendor states one.
- Terms are saved with retrieval dates, and re-checked when a vendor posts an update.
