The moderation object
The verdict, the scores, the evidence in details and your own context. Every field of a moderation, and when each one is present.
Every endpoint that returns a moderation returns the same object: the response to POST /v1/moderations, each entry of a batch, GET /v1/moderations/{id}, each row of the list and data.moderation in a webhook event. Read it once and you can read all of them.
The object never echoes the content you sent. It carries what Infrared concluded about it.
{
"object": "moderation",
"id": "mod_7ZgXCne4LiwQrsodlx4R8U",
"template": { "slug": "listing", "version": 1 },
"type": "text",
"field": "description",
"status": "completed",
"flagged": true,
"recommendation": "review",
"severity": "critical",
"policies": {
"personal_data": 0.75,
"lookalike_characters": 0,
"wordlist/competitors": 0,
"duplicate": 0,
"profanity": 0,
"hate_speech": 0,
"toxicity": 0,
"violence": 0,
"self_harm": 0,
"sexual": 0,
"spam": 0,
"links_contact": 0.9,
"illicit": 0,
"gibberish": 0,
"made_with_ai": 0,
"instructions": 0.8,
"guideline/no-off-site-deals": 1,
"screenshot": 0,
"image_quality": 0,
"watermark": 0
},
"triggered": ["personal_data", "guideline/no-off-site-deals", "instructions"],
"rule": { "id": "r6", "name": "Links from new accounts", "action": "review" },
"reasons": [
"trigger:personal_data:flag",
"trigger:guideline/no-off-site-deals:flag",
"trigger:instructions:flag",
"rule:r6"
],
"details": {
"personal_data": {
"labels": ["phone"],
"matches": [{ "label": "phone", "value": "+44 7700 900123", "start": 88, "end": 103 }],
"masked_output": "Solid oak, minor marks on one leg. Order direct at https://shop.example.com/oak or call +44***23",
"field": "description"
},
"links_contact": {
"labels": ["url", "phone"],
"matches": [
{ "label": "url", "value": "https://shop.example.com/oak", "start": 51, "end": 79 },
{ "label": "phone", "value": "+44 7700 900123", "source": "model" }
],
"field": "description"
},
"instructions": {
"labels": ["confidence:90"],
"matches": [{ "label": "evidence", "value": "Order direct at https://shop.example.com/oak or call +44 7700 900123", "field": "description" }],
"explanation": "The description directs users to an external website and provides a phone number, which violates the policy against off-site deals.",
"field": "description"
}
},
"author": { "id": "aut_1reK9hfk33nRTsdZpGN25v", "external_id": "user_42", "status": "enabled", "trust_level": "new", "known": true },
"language": "en",
"usage": { "checks": 0, "cached": false }, // sent with a test key, which uses none
"latency_ms": 3073,
"dry_run": false,
"test": true,
"content_id": "listing_18342",
"context_id": null,
"metadata": null,
"created_at": "2026-10-08T08:54:58.214Z",
"completed_at": "2026-10-08T08:55:01.913Z"
}This is the description of a listing from Moderate text, sent to a template named listing that has a guideline, a wordlist and AI instructions of its own.
What was moderated
idstringmod_and 22 characters. Use it to fetch the moderation, to re-moderate it and to match a webhook event.templateobjectThe
slugof the template that ran and theversionof it.basicis the built-in check. A moderation keeps the version it ran on when the template changes later.typestringWhat was sent.
formis the parent of a whole form.One of
textimageformfieldstringThe template field this object is. Present on a single object sent with
fieldand on every child of a form.fieldsmapPresent on a form only: one moderation per content field, keyed by field key.
parent_idstringPresent on a child of a form only: the
idof its parent.
The verdict
statusstringWhere the moderation stands. Read it first: the fields below mean something only once it is no longer
screening. Statuses and errors describes each one.One of
screeningcompletedpartialfailedinvalidflaggedbooleantruewhen a trigger with the flag effect fired, and on a submission that failed validation. This is the SAFE or FLAGGED verdict.recommendationstringWhat to do with the content.
nullwhilescreeningand on afailedrun.One of
allowreviewrejectseveritystringThe band of the highest weighted score.
nullwhilescreeningand on afailedrun.One of
nonelowmediumhighcriticalpoliciesmapA score from 0 to 1 for every policy the template enables, keyed by policy. Empty while
screeningand onfailedandinvalidmoderations.triggeredarray of stringsThe keys of the policies whose trigger fired, each once.
ruleobjectThe content rule that decided, as
id,nameandaction.nullwhen severity triage decided.reasonsarray of stringsThe path to the decision, step by step. How a decision is made lists every value.
The evidence
details holds what each policy found, keyed by policy. A policy appears there when it has something to say. On an object that names a field, every policy that ran appears, at least with that field's key.
| Key | Type | What it holds |
|---|---|---|
labels | array of strings | Sub-labels of the finding: insult, phone, url. Also marks the pipeline adds: ocr for a finding in text read from an image, confidence:90 on AI instructions and guidelines. |
matches | array of objects | The pieces of evidence. Their shape depends on the policy, as listed below. |
masked_output | string | personal_data only: the text with every finding masked, ready to store or show. |
canonical_term | string | Wordlists only: the canonical form of the first term that matched. |
explanation | string | AI instructions and guidelines: one or two sentences on why. Image policies: a one-sentence description of the picture. |
field | string | The field the result belongs to, or the field a whole-form finding is about. |
cached | boolean | true when the result came from the result cache. |
error | string | The policy did not answer. Its score is then missing from policies. |
| Policy | One entry of matches |
|---|---|
personal_data | label (email, phone, iban, card, national_id, address), value, start, end |
links_contact | label (url, messenger, off_platform, phone, email) and value. A pattern match adds start and end. A contact the model found adds source: "model". |
toxicity, hate_speech, spam and the other model-backed text policies | label, value (a quote of up to 200 characters) and sometimes a reason |
lookalike_characters | label (mixed_script, invisible), value (the word as written) |
wordlist/<slug> | label (the list's mode), value (the word that matched), term, canonical, similarity, start, end |
duplicate | label (same_author, other_author), value (the earlier submission's content_id, or null), created_at |
instructions, guideline/<slug> | label: "evidence", value (a quote), field |
validation_errors is present on an invalid moderation and lists what failed. error is present on a failed one.
Your context
authorobjectThe author as the decision saw them:
id, yourexternal_id,status,trust_levelandknown.nullwhen the request carried noauthor_id. The trust level is the one used for this decision, before this moderation was counted. In a 202 body and in list rows the object holdsidandexternal_idonly.content_idstringYour id for the content, as sent.
nullwhen you sent none.context_idstringYour grouping key, as sent.
metadataobjectYour own keys and values, as sent.
languagestringThe ISO 639-1 code of the text's language.
nullfor an image and for text too short to tell.
Authors, content ids and metadata shows how to send these and how to search by them.
Accounting and time
usageobjectchecksis the number of checks this moderation used.cachedistruewhen every result came from the result cache. A child of a form reports 0: its parent carries the cost.latency_msintegerHow long the screening run took, in milliseconds, not counting time spent in the queue.
nullwhilescreening.dry_runbooleantruewhen the request or the project asked for a dry run.testbooleantruewhen the request used a test key. The field is left out otherwise, so test for its presence.created_atstringWhen the request was accepted, as an ISO 8601 time in UTC.
completed_atstringWhen the run ended.
nullwhilescreening.
Scores are rounded, decisions are not
policies shows two decimals. The decision uses the unrounded score, so a policy shown as 0.7 can sit a hair under a threshold of 0.70 and not trigger.
A policy the template enables that did not run on this content, such as an image policy on a text, is listed with 0. A policy that failed is not listed at all: look for its key in details with an error.
Positions follow the normalised text
start and end in matches, and the whole of masked_output, refer to the text after normalisation: invisible characters removed, lookalike letters folded, whitespace collapsed. They line up with your input only when normalisation changed nothing.
To show a user where the problem is, quote value or show masked_output. Do not cut your original string by start and end.
Rows of the list
GET /v1/moderations returns the same object with three differences. A form comes without fields: fetch it by id to get its children. author holds id and external_id only. details is present for as long as the stored response is kept.
After the retention date
A moderation outlives its content. Past the retention date the scores, the verdict, reasons and validation_errors remain, while metadata becomes null and details loses its quotes: matches, masked_output and explanation are removed and labels stay. On a plan that stores no content this happens within a day. Data retention has the schedule.
In the dashboard
The Live console shows the same object: the verdict card, the score and evidence of each policy, and under Response the JSON your integration received.
Next
- How a decision is madeTriggers set the verdict, severity ranks the content, your content rules decide first and triage decides the rest. reasons records the path taken.
- Statuses and errorsThe five statuses a moderation can have and every error the moderation endpoints return, with the HTTP status, the code and what to do next.
- Authors, content ids and metadataFive optional fields tie a moderation to your own data. They say who wrote the content, which object it is, what it belongs to and whether it is stored.
- Data retention and privacyWhat Infrared keeps of a moderation, for how long, and what the nightly purge removes. Set it for a project, a template or a single request.
Something missing or unclear on this page? Write to support@useinfrared.com.
