Skip to main content

Policies

PUT/v1/policies/{tenant_id}/{app_id}/{agent_id}/{env}

Upsert Policy

Create or update full policy for a scope. Creates a new version each time. Returns the created version. **Authorization**: API key must be allowed to modify this app_id.

CI or Admin tokenscope: writeoperation_id: policies.upsert

Authentication

Requires a CI- or admin-level token. Runtime tokens are rejected for mutations.

SDK install

pip install znyx-sdknpm install @znyx/sdk

Path parameters

NameTypeRequiredDescription
tenant_id#pathstringrequired
app_id#pathstringrequired
agent_id#pathstringrequired
env#pathstringrequired

Header parameters

NameTypeRequiredDescription
x-created-by#headerstringoptional

Request bodyrequired

FieldTypeRequiredDescription
policyobjectrequiredFull policy JSON configuration
change_reasonstring | nulloptionalReason for this change

Responses

StatusDescription
200Successful Response
422Validation Error

Response schema

tenant_idrequiredstring | null
app_idrequiredstring
agent_idrequiredstring
envrequiredstring
version_numberrequiredinteger
policyrequiredobject
created_atrequiredstring
created_byrequiredstring

Errors & what triggers them

CodeTriggerFix
403Caller is not authorized for this app_id (X-API-Key or JWT scope mismatch).
422Policy JSON failed schema validation — unknown detector, bad threshold.
500Database contention while writing the new version.Retry once with fresh `If-Match` if your client sends it.

Notes & examples

How versioning works

Every call creates a new PolicyVersion row with version_number = latest + 1 and flips it to active. The previous version is retained for rollback — you can always go back with POST .../rollback/{version}.

Authoring flow

1. GET ...?resolved=true to see the current merged policy. 2. Edit the JSON locally (or in the Console's Configure page). 3. PUT the new version with a change_reason — this shows up in the audit log and the UI's Version History drawer. 4. The runtime picks up the new policy within ~60s (or immediately if you use the /v1/bundles/latest ETag poll).

Change reason

Always set change_reason. A month from now you'll want to know *why* PII was upgraded from REDACT to BLOCK. Examples of useful values:

  • "Tightened PII for EU customers — legal review ticket LEG-4312"
  • "Disabled hallucination for /support agent — too many false positives"
  • "Enabled toxicity for marketing bot — compliance requirement"
  • PATCH .../detector/{name} — change one detector only. Less blast radius.
  • GET .../history — version history.
  • POST /v1/orgs/.../bundles/publish — bake the current policies into a signed bundle for runtimes.

Request

curl -X PUT 'https://api.znyx.ai/v1/policies/00000000-0000-0000-0000-000000000000/00000000-0000-0000-0000-000000000000/00000000-0000-0000-0000-000000000000/prod' \
  -H 'Authorization: Bearer $ZNYX_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{
  "change_reason": "Updated PII policy for compliance",
  "policy": {
    "jailbreak": {
      "enabled": true,
      "threshold": 50
    },
    "pii": {
      "action": "BLOCK",
      "enabled": true
    }
  }
}'

Response

application/json

Successful Response

{
  "tenant_id": null,
  "app_id": "string",
  "agent_id": "string",
  "env": "string",
  "version_number": 0,
  "policy": {},
  "created_at": "string",
  "created_by": "string"
}

Schema: object