Skip to main content
This page is your reference when something doesn’t go to 200. Use the Verdicts page for what to do with the verdict inside a 200 response; this page is for protocol failures.

Error codes

Rate limits

Three layers stack: per‑second limits, per‑App quotas, and license quota.

Per‑second rate limits

When you exceed these limits you get 429 with no code field and a Retry-After header.

Per‑App event quotas

Set max_events_per_hour and / or max_events_per_day on the App. When hit, the response is:
  • HTTP 429
  • code: "APP_QUOTA_EXCEEDED"
  • Retry-After: 60 (hourly) or 3600 (daily)
Useful for capping spend on staging Apps and for isolating noisy customers under the same workspace.

License quota

Each call consumes one unit from the workspace’s monthly call quota. Batch items count individually. The 402 response body:

Fail‑closed behaviour

If the firewall service is down, scan endpoints fail with 503. Your application should treat this as deny‑by‑default. Letting prompts through unscored is exactly what the firewall is meant to prevent. The /health endpoint reports liveness; integrate it into your readiness probe if you operate the firewall in self‑hosted mode. That’s the whole‑service‑down case. There’s a narrower one: the service is up, but the ML injection classifier itself errors mid‑request (a transient inference failure). By default (RUNTIME_SECURITY_FAIL_MODE=open) the scan proceeds on whatever other signals are available (PII detectors, structural markers, phrase pack) rather than failing the whole call. Set RUNTIME_SECURITY_FAIL_MODE=closed to force verdict=block (blocked_reason=detector_error:fail_closed) instead: the stricter posture for deployments that would rather over‑block than let anything through unscored by the primary classifier. Separately, a proxy request with an attachment that can’t be turned into scannable text (oversized, unsupported type, extraction failure, an image with no OCR text) is silently forwarded unscanned by default, a potential scan bypass. Set RUNTIME_SECURITY_FILE_ANALYSIS_BLOCK_UNSCANNABLE=true to instead block it (blocked_reason=attachment_unscannable:<kind>).

FAQ

The verdict is information your application needs: blocked_reason, uuid, the score, the matching phrase. Returning 200 with the verdict in the body keeps that contract clean. Non‑200 codes are reserved for protocol failures (auth, rate limit, quota) where the client genuinely cannot retrieve a verdict.
redacted_text has any detected PII replaced with <CATEGORY> markers. On verdict: allow, redacted_text equals the original. On redact, forward redacted_text to your model. On block, neither field should be sent; surface a refusal to your user.
Not directly, but you can set the redact threshold very high (e.g. 1.1) so the API surface stays consistent without ever producing a redact verdict from injection score. Custom PII rules can be removed individually via the custom‑rules endpoint.
Check injection.meta.normalized in the response. When the firewall canonicalised the input (NFKC, zero‑width strip, Cyrillic confusables undo, leet undo), this flag is true and injection.meta.phrase_hits shows what matched.
The dashboard’s Runtime Security tab shows verdict timelines, the event log, and the drift surface. Or hit /analytics and /events programmatically. See Observability.
Recommended. Cloning a production App into a staging_… clone gives you separate quotas, separate event streams, and config‑version history that doesn’t pollute production drift charts. Use POST …/apps/{id}/clone to seed it.
No. Apps are workspace‑scoped, that’s the boundary both the API key and the App‑Id header check. Cross‑workspace traffic is rejected as APP_NOT_FOUND regardless of credentials.
Run both for a few days. Point a fraction of traffic at the proxy via a feature flag and watch the verdict mix on the dashboard for both paths. Once the proxy mix matches what the scan API produced, flip the rest.