Documentation
Everything you need to add runtime AI policy enforcement to your application in minutes.
From signup to your first proxied request — follow these steps in order.
sg_live_a1b2c3d4e5f6... # your key — keep it secret
block— block requests that match a jailbreak patternredact— strip PII (SSN, credit cards, emails) before they reach OpenAIallow— pass through with full audit logging
api.openai.com/v1 with sentinelgate.polsia.app/v1 and swap your API key for your sg_live_* key.curl https://sentinelgate.polsia.app/v1/chat/completions \ -H "Authorization: Bearer sg_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [ { "role": "user", "content": "Hello!" } ] }'
X-SentinelGate-Action confirming the policy decision.curl https://sentinelgate.polsia.app/api/audit \ -H "Authorization: Bearer sg_live_YOUR_KEY"
sentinelgate.polsia.app/v1 is now inspected, policy-enforced, and audited per your account.
SentinelGate sits between your app and the OpenAI API. Every request passes through the policy engine before reaching OpenAI.
Your App ↓ POST /v1/chat/completions (with sg_live_* key) SentinelGate ↓ Resolve API key → user + policy ↓ Apply rules: block / redact / mask / allow ↓ Log audit event to PostgreSQL ↓ Relay request → OpenAI (with your BYOK key) OpenAI ↑ Response streamed back SentinelGate ↑ Attach X-SentinelGate-* response headers Your App ↑ OpenAI-identical response
The proxy is fully transparent — no SDK changes required, no response format changes. Drop it in with a single base URL swap.
Proxy Endpoint
OpenAI-compatible chat completions endpoint. Accepts the same request body as OpenAI's Chat Completions API — no changes required.
Authentication
Pass your sg_live_* key in the Authorization header. Do not use your OpenAI key here — SentinelGate uses your saved BYOK key internally.
Authorization: Bearer sg_live_...
Request Body
| Field | Type | Status | Description |
|---|---|---|---|
| model | string | required | OpenAI model ID (e.g. gpt-4o, gpt-4o-mini) |
| messages | array | required | Array of message objects with role and content |
| temperature | number | optional | Sampling temperature (0–2) |
| max_tokens | integer | optional | Maximum tokens in response |
| stream | boolean | optional | Stream the response (SSE) |
Response Headers
| Header | Example | Description |
|---|---|---|
| X-SentinelGate-RequestId | sg_req_abc123 |
Unique audit event ID |
| X-SentinelGate-Action | allow |
Policy decision: allow, redact, or block |
| X-SentinelGate-Policy | My Policy |
Name of the active policy |
| X-SentinelGate-Latency | 312 |
Total latency in milliseconds |
Status Codes
Audit Logs
Paginated list of audit events scoped to your account. Newest events first.
Query Parameters
| Param | Type | Default | Description |
|---|---|---|---|
| page | integer | 1 |
Page number |
| limit | integer | 25 |
Events per page (max 100) |
| action | string | — | Filter by action: allow, block, redact |
Example Response
{
"success": true,
"events": [
{
"request_id": "sg_req_abc123",
"timestamp": "2026-03-20T06:00:00Z",
"model": "gpt-4o-mini",
"action": "allow",
"policy_name": "Default",
"rules_applied": [],
"latency_ms": 312,
"upstream_status": 200
}
],
"pagination": {
"page": 1,
"limit": 25,
"total": 142,
"pages": 6
}
}
Aggregated stats for the last N hours — total requests, blocked/allowed/redacted counts, avg latency, unique tenants.
Query Parameters
| Param | Type | Default | Description |
|---|---|---|---|
| hours | integer | 24 |
Lookback window in hours (max 168 = 7 days) |
Example Response
{
"success": true,
"period_hours": 24,
"stats": {
"total_requests": "142",
"allowed": "130",
"blocked": "5",
"redacted": "7",
"avg_latency_ms": "298"
},
"recent_blocks": [...]
}
Policies
List all policies for your account.
Create a new policy.
Request Body
| Field | Type | Status | Description |
|---|---|---|---|
| name | string | required | Unique policy name for your account |
| description | string | optional | Human-readable description |
| rules | array | optional | Array of rule objects (see below) |
| is_active | boolean | optional | Activate immediately (deactivates others) |
Rule Object
{
"type": "keyword", // "keyword" | "pattern" | "jailbreak" | "pii"
"action": "block", // "block" | "redact" | "mask" | "allow"
"pattern": "ignore all", // regex or keyword string
"description": "Block prompt injection attempts"
}
Update an existing policy. Same body shape as POST. Activating a policy deactivates all others.
Delete a policy. Cannot delete the active policy.
Audit events scoped to a specific policy ID. Supports ?page and ?limit.
All API endpoints (both proxy and management) authenticate via Bearer token in the Authorization header.
Authorization: Bearer sg_live_YOUR_API_KEY
API keys are in the format sg_live_ followed by 64 hex characters. They are hashed (SHA-256) before storage — SentinelGate cannot recover your key if lost. Generate a new one from the dashboard.
All errors return JSON with a success: false flag and a message field.
{
"success": false,
"message": "No LLM API key configured. Add one in the dashboard."
}
| Status | Meaning |
|---|---|
400 | Bad request — missing or invalid fields |
401 | Unauthorized — API key missing, invalid, or revoked |
403 | Blocked by policy — request matched a block rule |
404 | Resource not found |
409 | Conflict — e.g. duplicate policy name |
500 | Internal error or upstream (OpenAI) error |
Python (openai SDK)
from openai import OpenAI client = OpenAI( api_key="sg_live_YOUR_SENTINELGATE_KEY", base_url="https://sentinelgate.polsia.app/v1" ) response = client.chat.completions.create( model="gpt-4o-mini", messages=[ {"role": "user", "content": "Hello!"} ] ) print(response.choices[0].message.content)
That's the only change. Replace your existing api_key with your sg_live_* key and add base_url. The entire OpenAI SDK works as-is.
Streaming
with client.chat.completions.stream( model="gpt-4o-mini", messages=[{"role": "user", "content": "Tell me a story"}] ) as stream: for chunk in stream.text_stream: print(chunk, end="", flush=True)
Node.js (openai SDK)
import OpenAI from 'openai'; const client = new OpenAI({ apiKey: 'sg_live_YOUR_SENTINELGATE_KEY', baseURL: 'https://sentinelgate.polsia.app/v1' }); const response = await client.chat.completions.create({ model: 'gpt-4o-mini', messages: [ { role: 'user', content: 'Hello!' } ] }); console.log(response.choices[0].message.content);
CommonJS
const OpenAI = require('openai'); const client = new OpenAI({ apiKey: 'sg_live_YOUR_SENTINELGATE_KEY', baseURL: 'https://sentinelgate.polsia.app/v1' });
Check response headers
const response = await fetch('https://sentinelgate.polsia.app/v1/chat/completions', { method: 'POST', headers: { 'Authorization': 'Bearer sg_live_YOUR_KEY', 'Content-Type': 'application/json' }, body: JSON.stringify({ model: 'gpt-4o-mini', messages: [{ role: 'user', content: 'Hello!' }] }) }); console.log(response.headers.get('X-SentinelGate-Action')); // "allow" console.log(response.headers.get('X-SentinelGate-RequestId')); // "sg_req_..."
curl
# Basic request curl https://sentinelgate.polsia.app/v1/chat/completions \ -H "Authorization: Bearer sg_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "gpt-4o-mini", "messages": [{ "role": "user", "content": "Hello!" }] }' # Show response headers (see X-SentinelGate-*) curl -i https://sentinelgate.polsia.app/v1/chat/completions \ -H "Authorization: Bearer sg_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{"model":"gpt-4o-mini","messages":[{"role":"user","content":"Hello!"}]}' # List audit events curl https://sentinelgate.polsia.app/api/audit \ -H "Authorization: Bearer sg_live_YOUR_KEY" # Get stats for the last 48 hours curl "https://sentinelgate.polsia.app/api/audit/stats?hours=48" \ -H "Authorization: Bearer sg_live_YOUR_KEY" # List policies curl https://sentinelgate.polsia.app/api/policies \ -H "Authorization: Bearer sg_live_YOUR_KEY" # Create a policy curl -X POST https://sentinelgate.polsia.app/api/policies \ -H "Authorization: Bearer sg_live_YOUR_KEY" \ -H "Content-Type: application/json" \ -d '{ "name": "Production Policy", "rules": [ { "type": "jailbreak", "action": "block", "description": "Block jailbreak attempts" }, { "type": "pii", "action": "redact", "description": "Strip PII before OpenAI" } ], "is_active": true }'