Policy Management
Create and manage guardrails for your AI applications
Overview
Manage security policies for Cygnal. Create, list, update, and delete policies; export and import; view version history. Policies define rules, thresholds, modes, and optional scanner config used by Cygnal.
Authentication
All policy endpoints require a valid Gray Swan API key. You can pass it in either header:
Authorization: Bearer <api_key>x-api-key: <api_key>
List, get, export, and version endpoints are available to any organization
user. Create, update, delete, and import require an admin for the
organization. Non-admin calls to those endpoints return 403
ADMIN_REQUIRED.
Endpoints
| Method | Path | Description | Admin Required |
|---|---|---|---|
| GET | /policies | List all policies | X |
| GET | /policies/export | Export all policies | X |
| GET | /policies/{policy_id} | Get one policy | X |
| GET | /policies/{policy_id}/export | Export one policy | X |
| GET | /policies/{policy_id}/versions | List version history | X |
| GET | /policies/{policy_id}/versions/{version_id} | Get policy at version | X |
| POST | /policies | Create policy | ✓ |
| POST | /policies/import | Import one policy | ✓ |
| POST | /policies/bulk-import | Bulk import (1–100) | ✓ |
| PUT | /policies/{policy_id} | Update policy (no presets) | ✓ |
| DELETE | /policies/{policy_id} | Delete policy (no presets) | ✓ |
List Policies
GET /policies
Returns policies for the organization, sorted by most recently updated. By default (no limit), returns all policies. When limit is provided, uses offset pagination.
Query Params
limit(integer, optional): Maximum number of policies to return. If omitted, returns all policies. Min1, max1000when provided.offset(integer, optional): Number of policies to skip. Default0, min0
Response
Returns a PolicyListResponse object:
policies: array of policy objectstotal: total number of policies (regardless of limit)limit: applied limit (nullif no limit was applied)offset: applied offsethas_more: boolean indicating if more results are available beyond the current page (onlytruewhen limit is applied and more results exist)
import os
import requests
# Get all policies (no pagination)
response = requests.get(
"https://api.grayswan.ai/policies",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
},
)
data = response.json()
print(f"Total policies: {data['total']}")
print(f"Policies returned: {len(data['policies'])}")
# Get paginated results
response = requests.get(
"https://api.grayswan.ai/policies",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
},
params={
"limit": 50,
"offset": 0,
},
)
data = response.json()
print(f"Has more: {data['has_more']}")Export All Policies
GET /policies/export
import os
import requests
response = requests.get(
"https://api.grayswan.ai/policies/export",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
},
)Get Policy by ID
GET /policies/{policy_id}
import os
import requests
policy_id = "YOUR_POLICY_ID"
response = requests.get(
f"https://api.grayswan.ai/policies/{policy_id}",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
},
)Export Policy by ID
GET /policies/{policy_id}/export
import os
import requests
policy_id = "YOUR_POLICY_ID"
response = requests.get(
f"https://api.grayswan.ai/policies/{policy_id}/export",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
},
)List Versions
GET /policies/{policy_id}/versions
import os
import requests
policy_id = "YOUR_POLICY_ID"
response = requests.get(
f"https://api.grayswan.ai/policies/{policy_id}/versions",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
},
)Get Policy at Version
GET /policies/{policy_id}/versions/{version_id}
import os
import requests
policy_id = "YOUR_POLICY_ID"
version_id = "VERSION_ID"
response = requests.get(
f"https://api.grayswan.ai/policies/{policy_id}/versions/{version_id}",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
},
)Create Policy
POST /policies
import os
import requests
response = requests.post(
"https://api.grayswan.ai/policies",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
"Content-Type": "application/json",
},
json={
"name": "Strict policy",
"description": "Blocks unsafe requests",
"categories": {
"self_harm": "Detect self-harm guidance",
"illicit_behavior": "Detect criminal instructions"
},
"mode": "content_moderation",
"pre_violation_threshold": 0.6
},
)Import Policy
POST /policies/import
import os
import requests
response = requests.post(
"https://api.grayswan.ai/policies/import",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
"Content-Type": "application/json",
},
json={
"policy": {
"name": "Imported policy",
"description": "Imported from export payload",
"categories": {"abuse": "Detect abusive content"},
"mode": "content_moderation",
"pre_violation_threshold": 0.5,
"pre_jb_threshold": 0.3,
"post_violation_threshold": 0.5,
"post_violation_jb_threshold": 0.3
}
},
)IDs in payload are ignored and new IDs are generated.
Bulk Import Policies
POST /policies/bulk-import
import os
import requests
response = requests.post(
"https://api.grayswan.ai/policies/bulk-import",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
"Content-Type": "application/json",
},
json={
"policies": [
{
"name": "Policy A",
"categories": {"harassment": "Detect harassment"},
"mode": "content_moderation"
},
{
"name": "Policy B",
"categories": {"hate": "Detect hate speech"},
"mode": "content_moderation"
}
]
},
)Update Policy
PUT /policies/{policy_id}
import os
import requests
policy_id = "YOUR_POLICY_ID"
response = requests.put(
f"https://api.grayswan.ai/policies/{policy_id}",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
"Content-Type": "application/json",
},
json={
"description": "Updated policy description",
"post_violation_threshold": 0.45
},
)Delete Policy
DELETE /policies/{policy_id}
import os
import requests
policy_id = "YOUR_POLICY_ID"
response = requests.delete(
f"https://api.grayswan.ai/policies/{policy_id}",
headers={
"Authorization": f"Bearer {os.environ.get('GRAYSWAN_API_KEY')}",
},
)