Skip to content

Test a template

POST/v1/templates/{slug}/testKey scope moderate

Runs a sample submission through the template's full pipeline and returns the moderation it would produce, with no side effects. Nothing is stored, no check is consumed, no review queue item is created, no webhook event is sent and no author is created or updated. Use it to try a template, or its unpublished draft, before sending live traffic.

Needs a key with the moderate scope. Authentication

curl https://api.useinfrared.com/v1/templates/review/test \
  -H "Authorization: Bearer $INFRARED_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "fields": {
      "rating": 2,
      "body": "The courier left the parcel in the rain and the box was soaked through. The refund took three weeks."
    }
  }'
200 OKResponse
{
  "object": "moderation",
  "id": null,
  "template": {
    "slug": "review",
    "version": 1
  },
  "type": "form",
  "status": "completed",
  "flagged": false,
  "recommendation": "allow",
  "severity": "none",
  "policies": {
    "personal_data": 0,
    "lookalike_characters": 0,
    "profanity": 0,
    "hate_speech": 0,
    "toxicity": 0,
    "violence": 0,
    "self_harm": 0,
    "sexual": 0,
    "spam": 0,
    "links_contact": 0,
    "illicit": 0,
    "gibberish": 0,
    "off_topic": 0,
    "made_with_ai": 0,
    "instructions": 0
  },
  "triggered": [],
  "rule": null,
  "reasons": ["triage:allow"],
  "details": {
    "personal_data": {
      "field": "body"
    },
    "lookalike_characters": {
      "field": "body"
    },
    "profanity": {
      "field": "body"
    },
    "hate_speech": {
      "field": "body"
    },
    "toxicity": {
      "field": "body"
    },
    "violence": {
      "field": "body"
    },
    "self_harm": {
      "field": "body"
    },
    "sexual": {
      "field": "body"
    },
    "spam": {
      "field": "body"
    },
    "links_contact": {
      "field": "body"
    },
    "illicit": {
      "field": "body"
    },
    "gibberish": {
      "field": "body"
    },
    "off_topic": {
      "field": "body"
    },
    "made_with_ai": {
      "field": "body"
    },
    "instructions": {
      "labels": ["confidence:100"],
      "matches": [
        {
          "label": "evidence",
          "value": "The courier left the parcel in the rain and the box was soaked through. The refund took three weeks.",
          "field": "body"
        }
      ],
      "explanation": "The review describes a real experience with the service, detailing issues with delivery and refund processing.",
      "field": "body"
    }
  },
  "author": null,
  "language": "en",
  "usage": {
    "checks": 0,
    "estimated": 1,
    "cached": false
  },
  "latency_ms": 2713,
  "dry_run": false,
  "test": true,
  "content_id": null,
  "context_id": null,
  "metadata": null,
  "created_at": "2026-10-08T09:28:33.592Z",
  "completed_at": "2026-10-08T09:28:33.592Z",
  "fields": {
    "body": {
      "object": "moderation",
      "id": null,
      "template": {
        "slug": "review",
        "version": 1
      },
      "type": "text",
      "field": "body",
      "status": "completed",
      "flagged": false,
      "recommendation": "allow",
      "severity": "none",
      "policies": {
        "personal_data": 0,
        "lookalike_characters": 0,
        "profanity": 0,
        "hate_speech": 0,
        "toxicity": 0,
        "violence": 0,
        "self_harm": 0,
        "sexual": 0,
        "spam": 0,
        "links_contact": 0,
        "illicit": 0,
        "gibberish": 0,
        "off_topic": 0,
        "made_with_ai": 0
      },
      "triggered": [],
      "rule": null,
      "reasons": ["triage:allow"],
      "details": {
        "personal_data": {
          "field": "body"
        },
        "lookalike_characters": {
          "field": "body"
        },
        "profanity": {
          "field": "body"
        },
        "hate_speech": {
          "field": "body"
        },
        "toxicity": {
          "field": "body"
        },
        "violence": {
          "field": "body"
        },
        "self_harm": {
          "field": "body"
        },
        "sexual": {
          "field": "body"
        },
        "spam": {
          "field": "body"
        },
        "links_contact": {
          "field": "body"
        },
        "illicit": {
          "field": "body"
        },
        "gibberish": {
          "field": "body"
        },
        "off_topic": {
          "field": "body"
        },
        "made_with_ai": {
          "field": "body"
        },
        "instructions": {
          "labels": ["confidence:100"],
          "matches": [
            {
              "label": "evidence",
              "value": "The courier left the parcel in the rain and the box was soaked through. The refund took three weeks.",
              "field": "body"
            }
          ],
          "explanation": "The review describes a real experience with the service, detailing issues with delivery and refund processing.",
          "field": "body"
        }
      },
      "author": null,
      "language": "en",
      "usage": {
        "checks": 0,
        "cached": false
      },
      "latency_ms": null,
      "dry_run": false,
      "test": true,
      "content_id": null,
      "context_id": null,
      "metadata": null,
      "created_at": "2026-10-08T09:28:33.592Z",
      "completed_at": null
    }
  }
}

Path parameters

slugstringRequired

Slug of the template to test. It replaces any template sent in the body.

Request body

A single object

templatestring

Accepted and ignored. The template is the one named in the path.

content_idstring

Your id for the object, up to 200 characters. It is returned with the result and read by duplicate detection as in a live request.

author_idstring

Your id for the end user, up to 200 characters. An existing author's status and trust level are applied to the content rules. An unknown id is treated as a new, enabled author and no author is created.

context_idstring

Your id for what the content belongs to, up to 200 characters. It is returned with the result.

metadatamap

Up to 50 key and value pairs, returned with the result. Same limits as on POST /v1/moderations.

modeenumDefault auto

Accepted and ignored. A test always runs in the request and answers 200.

One ofautosyncasync

dry_runboolean

Returned as dry_run in the result. It changes nothing else, because a test has no side effects.

storeboolean

Accepted and ignored. A test stores nothing.

client_actionobject

Your own decision about the sample, applied after the content rules and severity triage as in a live request.

actionenumRequired

escalate replaces the recommendation only when yours is stricter. override always replaces it.

One ofescalateoverride

recommendationenumRequired

The recommendation to apply: allow, review or reject.

One ofallowreviewreject

typeenumDefault text

The kind of content in input: text (default) or image. audio and video are in development and answer 400 not_supported_yet.

One oftextimageaudiovideo

inputstring or URL or array of URLsRequired

The sample content of a single object: a string of up to 20,000 characters for text, or one or more image URLs for image. Same limits as on POST /v1/moderations.

fieldstring

Key of the template field the sample is. Without it, every field-level trigger of the template is applied to the sample.

draftboolean

Set to true to run the template's unpublished draft version. When the template has no draft, the published version runs. Default false.

A whole form

templatestring

Accepted and ignored. The template is the one named in the path.

content_idstring

Your id for the object, up to 200 characters. It is returned with the result and read by duplicate detection as in a live request.

author_idstring

Your id for the end user, up to 200 characters. An existing author's status and trust level are applied to the content rules. An unknown id is treated as a new, enabled author and no author is created.

context_idstring

Your id for what the content belongs to, up to 200 characters. It is returned with the result.

metadatamap

Up to 50 key and value pairs, returned with the result. Same limits as on POST /v1/moderations.

modeenumDefault auto

Accepted and ignored. A test always runs in the request and answers 200.

One ofautosyncasync

dry_runboolean

Returned as dry_run in the result. It changes nothing else, because a test has no side effects.

storeboolean

Accepted and ignored. A test stores nothing.

client_actionobject

Your own decision about the sample, applied after the content rules and severity triage as in a live request.

actionenumRequired

escalate replaces the recommendation only when yours is stricter. override always replaces it.

One ofescalateoverride

recommendationenumRequired

The recommendation to apply: allow, review or reject.

One ofallowreviewreject

fieldsmapRequired

A sample of a whole form: an object of 1 to 40 entries that maps each template field key to its value. Not accepted together with input, type or field.

draftboolean

Set to true to run the template's unpublished draft version. When the template has no draft, the published version runs. Default false.

Returns

A moderation whose id is null and whose test is true, always with status 200. usage.checks is 0 and usage.estimated is the number of checks the same submission would consume in a live request. For a form, the moderations under fields have a null id as well.

Errors

400
not_supported_yet

The sample carries audio or video.

403
plan_limit

The organisation's plan does not include templates and the slug is not basic.

404
template_not_found

The project has no template with this slug, or the template is archived.

409
template_not_published

The template has no published version and draft is not true.

422
validation_error

The body matches neither moderation shape: it has an unknown key, both input and fields, or neither of them.

Every endpoint can also answer the errors any request can meet: a missing key, a rate limit, a malformed body. Errors

Something missing or unclear on this page? Write to support@useinfrared.com.