A policy is the detector exception list for one project and environment. This endpoint reads it and publishes one profile's overrides. The SDKs do not manage policies - they only check text - so scripted changes go through here or the dashboard.
- Read the whole view with GET, for every profile
- Publish one profile with PUT; the body replaces that profile's overrides
- Leave a detector out and it returns to its default: enabled and enforcing
- Scoped by the key to one project and one environment
Endpoint
GET and PUT are served from https://api.verexa.dev/v1/policy, with the key as a Bearer token. The key selects the project and environment, so there is no project or environment field in the request.
Read the policy
A GET returns the current view:
curl https://api.verexa.dev/v1/policy \ -H "Authorization: Bearer $VEREXA_API_KEY"{ "profiles": { "balanced": { "detectors": { "output.markdown_exfil": { "enabled": true, "mode": "enforce" }, "output.secret_leak": { "enabled": true, "mode": "enforce" }, "prompt.injection_classifier": { "enabled": true, "mode": "monitor" }, "text.pii": { "enabled": false, "mode": "enforce" } } } }}The policy view
| Field | Holds |
|---|---|
profiles | The view, keyed by profile name |
detectors | A profile's overrides: detector id to an object with enabled and mode |
enabled | false removes the detector from the plan; true runs it |
mode | enforce lets the detector act as documented; monitor runs it but caps its action at flag |
A detector with no entry in a profile keeps the default: enabled and enforcing. Overrides exist per profile, so text.pii can be off on deterministic and monitored on balanced. The judge is not on the list - whether it reviews a verdict comes from the profile. See Policies for the full picture.
Publish a policy
A PUT replaces the overrides stored for one profile:
curl -X PUT https://api.verexa.dev/v1/policy \ -H "Authorization: Bearer $VEREXA_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "profile": "balanced", "detectors": { "prompt.injection_classifier": { "enabled": true, "mode": "monitor" }, "text.pii": { "enabled": false, "mode": "enforce" } } }'- The profile is required and must be
deterministic,balancedoraudit - The body replaces that profile's overrides. Include every override you want to keep; a detector you leave out returns to its default
- To clear a profile, send an empty
detectorsobject - The response is the full view, the same shape the GET returns
false. A detector object like {"mode": "monitor"} disables the detector instead of monitoring it.How overrides apply
- On the next check. A publish affects checks that start after it; one already in flight finishes under the plan it started with
- No stale cache. The publish changes the profile's plan hash, and cached verdicts are keyed by it, so nothing cached under the old policy is served again
- Durably, when a store is configured. With a control-plane store the overrides survive restarts; without one they live in the service memory and reset on restart
- All or nothing. A publish that cannot be stored is rejected, and the policy already in force keeps serving
Errors
A failed request answers with a status code and a one-line plain-text body:
| Status | Body | When |
|---|---|---|
| 400 | invalid request body | The body is not valid JSON, or detectors is malformed |
| 400 | unknown profile | profile is missing or is not deterministic, balanced or audit |
| 401 | unauthorized | The key is missing, invalid or revoked |
| 405 | method not allowed | The path was called with a method other than GET or PUT |
| 500 | internal error | The request failed unexpectedly |
| 503 | policy store not configured | This deployment requires a control-plane store and none is configured |
| 503 | could not persist policy | The overrides could not be stored; the policy in force is unchanged |
Next steps
- Policies: monitor mode, scope and the dashboard flow
- Guardrails: every detector, its phase and its default action
- Check API: how overrides shape a verdict
- API reference: base URL, authentication and conventions