Moderation
Windpaint's content policy: what is blocked, the auto and low moderation levels, how blocked prompts and outputs are reported, and why they're never charged.
Windpaint checks prompts before a job is created and checks outputs after the model runs. Content that falls into a blocked category is refused, and you’re never charged for it.
Categories
| Category | Covers |
|---|---|
sexual/minors | Sexual content involving minors. Hard category. |
sexual/nonconsensual | Non-consensual intimate imagery of real people. Hard category. |
sexual | Sexual or explicit content. |
violence | Violence. |
violence/graphic | Graphic violence and gore. |
hate | Hate based on protected attributes. |
harassment | Harassment or threats. |
self-harm | Self-harm. |
illicit | Instructions or depictions of illegal activity. |
public_figure | Content depicting real public figures. |
provider_flagged | The model refused the request without giving a reason. |
Hard categories are blocked under every moderation level and can’t be relaxed.
Moderation levels
Submits to POST /v1/generation/capabilities/{capability} and POST /v1/generation/models/{model} take an optional moderation field:
moderation | Behavior |
|---|---|
auto (default) | Blocks content that is likely to fall into any category. |
low | Blocks only content that very clearly falls into a category. Hard categories are blocked as under auto. |
curl -X POST https://api.windpaint.ai/v1/generation/capabilities/image.generate \
-H "Authorization: Bearer $WINDPAINT_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": "a medieval battle scene, painted", "moderation": "low"}'
Any other value returns 422 request.validation_failed with details {"moderation": "<value>", "allowed": ["auto", "low"]}. Workflow runs always use auto.
Blocked prompts
The prompt is checked at submit, before any credits are held. Input images can be checked too, depending on how input checks are configured for your account; only the first 8 image inputs are checked. A blocked request returns 422 and no job is created:
{
"error": {
"code": "moderation.input_blocked",
"message": "The request was blocked by content moderation.",
"details": { "stage": "input", "categories": ["sexual"], "moderation": "auto" },
"request_id": "86926749.37e5a9"
}
}
There’s no request_id for the job because none was created, and nothing is held or charged. POST /v1/generation/estimate doesn’t run moderation, so an estimate can succeed for a prompt that submit rejects.
Blocked outputs
Image outputs are checked after the model runs. A blocked job ends with status nsfw:
{
"status": "nsfw",
"outputs": [],
"images": [],
"video": null,
"credits": { "estimate": "0.08", "actual": null },
"error": "The output was blocked by content moderation. Credits were released.",
"error_code": "moderation.output_blocked",
"moderation": {
"code": "moderation.output_blocked",
"stage": "output",
"categories": ["violence/graphic"]
}
}
No output is kept and the hold is released in full. When the model itself refuses, the job looks the same with categories: ["provider_flagged"] and error Generation blocked: the provider refused the content. Credits were released. moderation is null on every job that wasn’t blocked. The webhook for the job carries the same fields.
Video and audio outputs are not checked by Windpaint; they rely on the model’s own safety checks, which report as provider_flagged.
If a check can’t run, for example because a classifier errors or times out, the request isn’t blocked by that check.
In a workflow run, a step whose prompt is blocked fails with the moderation message, and the run fails the way it would for any failed step.
Enforcement
Windpaint records each block against your organization. Repeated blocks in a hard category flag the organization for review by Windpaint staff, who may contact you or restrict the account. Nothing is suspended automatically.
Blocked requests and outputs are never charged. If you think something was blocked by mistake, try moderation: "low" for a non-hard category, rephrase the prompt, or contact support with the request_id or the error’s request_id.