Proxy & API Deployment¶
SafeAI ships with a production-ready HTTP proxy built on FastAPI. Run it as a sidecar next to your AI service or as a centralised gateway — every scan, guard, intercept, memory, and audit operation is available over REST with full OpenAPI documentation.
1 — Starting the Proxy¶
Sidecar mode (default)¶
python -m safeai.cli.main serve \
--mode sidecar \
--host 127.0.0.1 \
--port 8910 \
--config safeai.yaml
Gateway mode¶
Gateway mode optionally forwards allowed requests to an upstream LLM provider:
python -m safeai.cli.main serve \
--mode gateway \
--host 0.0.0.0 \
--port 8910 \
--config safeai.yaml \
--upstream-base-url https://api.openai.com
Tip
In sidecar mode the proxy only exposes SafeAI endpoints. In gateway mode it can also forward traffic through /v1/proxy/forward after applying safety checks.
2 — Core HTTP Endpoints¶
All endpoints live under the /v1 prefix.
Health check¶
Scan input¶
Scan raw text before it reaches the LLM.
curl -s -X POST http://127.0.0.1:8910/v1/scan/input \
-H "Content-Type: application/json" \
-d '{
"text": "token=sk-ABCDEF1234567890ABCDEF",
"agent_id": "default-agent"
}' | python -m json.tool
{
"decision": {
"action": "block",
"reason": "Secret detected in input",
"policy_name": "default-secret-detection"
},
"detections": [
{
"type": "secret",
"value": "sk-ABCDEF1234567890ABCDEF",
"location": { "start": 6, "end": 32 }
}
]
}
Scan structured input¶
Scan nested JSON payloads — detections include JSON-path locations.
curl -s -X POST http://127.0.0.1:8910/v1/scan/structured \
-H "Content-Type: application/json" \
-d '{
"payload": {
"request": {
"token": "sk-ABCDEF1234567890ABCDEF",
"message": "deploy to production"
}
},
"agent_id": "default-agent"
}' | python -m json.tool
{
"decision": {
"action": "block",
"reason": "Secret detected in structured input"
},
"detections": [
{
"type": "secret",
"path": "$.request.token"
}
]
}
Scan file¶
Scan a file on disk (JSON files use structured mode automatically).
curl -s -X POST http://127.0.0.1:8910/v1/scan/file \
-H "Content-Type: application/json" \
-d '{
"path": "data.json",
"agent_id": "default-agent"
}' | python -m json.tool
Guard output¶
Redact PII and secrets before text reaches the user.
curl -s -X POST http://127.0.0.1:8910/v1/guard/output \
-H "Content-Type: application/json" \
-d '{
"text": "Contact alice@example.com or call 555-0100.",
"agent_id": "default-agent"
}' | python -m json.tool
{
"decision": {
"action": "redact",
"reason": "PII detected in output"
},
"safe_output": "Contact [EMAIL_REDACTED] or call [PHONE_REDACTED].",
"detections": [
{ "type": "email", "value": "alice@example.com" },
{ "type": "phone", "value": "555-0100" }
]
}
Intercept tool request¶
Validate a tool call against policies, contracts, and identity declarations before the tool executes.
curl -s -X POST http://127.0.0.1:8910/v1/intercept/tool \
-H "Content-Type: application/json" \
-d '{
"phase": "request",
"tool_name": "shell_exec",
"parameters": { "command": "rm -rf /" },
"data_tags": ["destructive"],
"agent_id": "default-agent",
"session_id": "sess-001"
}' | python -m json.tool
To guard the response from a tool, set "phase": "response" and include the tool output in "response".
Memory write / read¶
# Write
curl -s -X POST http://127.0.0.1:8910/v1/memory/write \
-H "Content-Type: application/json" \
-d '{
"key": "user_preference",
"value": "en-US",
"agent_id": "default-agent"
}' | python -m json.tool
# Read
curl -s -X POST http://127.0.0.1:8910/v1/memory/read \
-H "Content-Type: application/json" \
-d '{
"key": "user_preference",
"agent_id": "default-agent"
}' | python -m json.tool
Audit log¶
Metrics¶
Prometheus-format metrics for monitoring:
Policy reload¶
| Endpoint | Method | Purpose |
|---|---|---|
/v1/health | GET | Health check |
/v1/scan/input | POST | Scan text input |
/v1/scan/structured | POST | Scan nested JSON |
/v1/scan/file | POST | Scan file on disk |
/v1/guard/output | POST | Guard & redact output |
/v1/intercept/tool | POST | Intercept tool request or response |
/v1/memory/write | POST | Write to agent memory |
/v1/memory/read | POST | Read from agent memory |
/v1/audit | GET | Query audit events |
/v1/metrics | GET | Prometheus metrics |
/v1/policies/reload | POST | Hot-reload policies |
3 — Approval Workflow via API¶
Sensitive operations (e.g., accessing production databases) can require human approval before proceeding.
Step 1 — Trigger an approval-gated tool call¶
curl -s -X POST http://127.0.0.1:8910/v1/intercept/tool \
-H "Content-Type: application/json" \
-d '{
"phase": "request",
"tool_name": "database_query",
"parameters": { "query": "DELETE FROM users WHERE active = false" },
"data_tags": ["destructive", "pii"],
"agent_id": "default-agent",
"session_id": "sess-002"
}' | python -m json.tool
{
"decision": {
"action": "pending_approval",
"reason": "Human approval required for destructive database operation"
},
"approval_request_id": "ar-a1b2c3d4"
}
Step 2 — List pending approvals¶
[
{
"request_id": "ar-a1b2c3d4",
"agent_id": "default-agent",
"tool_name": "database_query",
"status": "pending",
"created_at": "2025-01-15T10:30:00Z"
}
]
Step 3 — Approve or deny¶
curl -s -X POST http://127.0.0.1:8910/v1/approvals/ar-a1b2c3d4/approve \
-H "Content-Type: application/json" \
-d '{
"approver_id": "security-admin",
"note": "Reviewed — safe to proceed with cleanup"
}' | python -m json.tool
Step 4 — Retry the tool call with approval¶
curl -s -X POST http://127.0.0.1:8910/v1/intercept/tool \
-H "Content-Type: application/json" \
-d '{
"phase": "request",
"tool_name": "database_query",
"parameters": { "query": "DELETE FROM users WHERE active = false" },
"data_tags": ["destructive", "pii"],
"agent_id": "default-agent",
"session_id": "sess-002",
"approval_request_id": "ar-a1b2c3d4"
}' | python -m json.tool
Note
Approval TTL is configurable in safeai.yaml under approvals.default_ttl. Expired approvals are automatically rejected.
4 — Dashboard¶
SafeAI includes a built-in web dashboard for real-time monitoring, audit browsing, and approval management.
Accessing the dashboard¶
When the proxy is running with dashboard.enabled: true in safeai.yaml, open:
RBAC roles¶
The dashboard supports role-based access control via the x-safeai-user and x-safeai-tenant headers:
| Role | Capabilities |
|---|---|
admin | Full access — policies, approvals, audit, config |
approver | View audit, approve / deny requests |
auditor | Read-only access to audit logs and metrics |
viewer | Read-only dashboard access |
Configure users in safeai.yaml:
dashboard:
enabled: true
rbac_enabled: true
user_header: x-safeai-user
tenant_header: x-safeai-tenant
users:
- user_id: security-admin
role: admin
tenants: ["*"]
- user_id: security-approver
role: approver
tenants: ["default"]
5 — WebSocket Events¶
Subscribe to a real-time event stream for live monitoring, alerting, or driving custom UIs.
Connect¶
Event format¶
Events are JSON objects pushed to all connected clients:
{
"event": "scan.blocked",
"timestamp": "2025-01-15T10:32:15Z",
"agent_id": "default-agent",
"detail": {
"boundary": "input",
"action": "block",
"detection_type": "secret"
}
}
Common event types¶
| Event | Fired when |
|---|---|
scan.allowed | Input scan passes all checks |
scan.blocked | Input scan triggers a block |
guard.redacted | Output guard redacts content |
intercept.blocked | Tool call blocked by policy |
intercept.pending_approval | Tool call awaiting human approval |
approval.approved | An approval request is approved |
approval.denied | An approval request is denied |
memory.write | Agent writes to memory |
policy.reloaded | Policies hot-reloaded from disk |
Tip
Use WebSocket events to feed dashboards, Slack bots, or PagerDuty integrations. Each event includes enough context to triage without querying the audit log.
6 — OpenAPI Documentation¶
The proxy auto-generates interactive API documentation from its FastAPI routes.
| URL | Format |
|---|---|
http://127.0.0.1:8910/docs | Swagger UI — interactive try-it-out console |
http://127.0.0.1:8910/redoc | ReDoc — clean reference documentation |
http://127.0.0.1:8910/openapi.json | Raw OpenAPI 3.x spec (JSON) |
Fetch the spec programmatically¶
{
"openapi": "3.1.0",
"info": {
"title": "SafeAI Proxy",
"version": "0.1.0"
},
"paths": {
"/v1/health": { "..." },
"/v1/scan/input": { "..." },
"/v1/guard/output": { "..." }
}
}
Use the spec to auto-generate client SDKs in any language, import into Postman, or validate requests in CI with spectral / openapi-diff.
Running as a Service¶
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN"
"http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>Label</key>
<string>com.safeai.proxy</string>
<key>ProgramArguments</key>
<array>
<string>/usr/bin/python3</string>
<string>-m</string>
<string>safeai.cli.main</string>
<string>serve</string>
<string>--mode</string>
<string>sidecar</string>
<string>--host</string>
<string>127.0.0.1</string>
<string>--port</string>
<string>8910</string>
<string>--config</string>
<string>/etc/safeai/safeai.yaml</string>
</array>
<key>RunAtLoad</key>
<true/>
<key>KeepAlive</key>
<true/>
</dict>
</plist>
Next Steps¶
- SDK Quick Start Examples — use all these endpoints from Python
- Proxy / Sidecar Integration — architecture patterns and deployment topologies
- Approval Workflows Guide — advanced approval chains and escalation
- Dashboard Reference — RBAC, alerting, and custom views
- Plugins Integration — extend the proxy with custom detectors
- API Reference — SafeAI — full method signatures and types