Reference

API Reference

All endpoints exposed by the Universal Guardrail FastAPI backend. Base URL: http://localhost:8000

Authentication

Every request needs either credential:

  • x-api-key header — a gateway key from GUARDRAIL_API_KEYS, or a GUARDRAIL-… license key (get one by email →)
  • Authorization: Bearer <JWT> — from POST /api/auth/token

Note: if GUARDRAIL_API_KEYS is unset (dev mode), key auth is disabled and JWT login still works. /api/auth/* endpoints are public by design.

curl -H "x-api-key: your-api-key" http://localhost:8000/api/analytics

Requests missing valid credentials receive 401 Unauthorized. The health check endpoint GET / does not require auth.

POST /api/license/purchase

Self-service key issuance — no auth required. Generates a signed GUARDRAIL-… license key and emails it to the buyer (the key is never shown on-screen or stored server-side in plaintext). Rate-limited to 5 req/min. Requires LICENSE_SECRET; email delivery uses SMTP_* env vars (dev mode without SMTP writes the email to logs/outbound_email.log).

Request Body

FieldTypeDescription
email requiredstring Delivery address (disposable domains rejected)
planstring "starter" (default, 5 seats / 3 apps) | "pro" (25/15) | "enterprise" (200/50). Licenses run 365 days.
POST /api/license/purchase
{ "email": "you@company.com", "plan": "pro" }

Response

{ "purchase": "ok", "sent_to": "you@company.com", "plan": "pro", "emailed": true }
# dev mode without SMTP configured:
{ "purchase": "ok", "emailed": false, "note": "check logs/outbound_email.log" }
POST /api/validate

Validates a prompt through all configured Input Rails without calling an LLM. Use this for standalone guardrail checks. Rate-limited to 50 req/min.

Request Body

Field Type Description
prompt required string The user input to validate
role string RBAC role for the user. Default: "intern". Must match a role in guard_config.yaml
history array Conversation history (array of message objects). Currently unused for validation but accepted.
POST /api/validate
{
  "prompt": "What is the company refund policy?",
  "role": "user"
}

Response

# Allowed
{ "allowed": true, "response": null, "sanitized_prompt": "What is the company refund policy?" }

# Blocked
{ "allowed": false, "response": "⚠️ Security Alert: Potential Secret/API Key detected." }

# Flagged (allowed but with warning)
{ "allowed": true, "response": "⚠️ Warning: Abusive language detected.", "sanitized_prompt": "..." }
POST /api/chat

Full guardrail pipeline: Input Rails → LLM → Output Rails. The recommended integration point for most applications. Rate-limited to 20 req/min.

Request Body

Field Type Description
prompt required string The user message to process
role string RBAC role. Default: "intern"
history array Prior conversation messages for context
POST /api/chat
{
  "prompt": "Explain our return policy",
  "role": "user",
  "history": [
    { "role": "user", "content": "Hello" },
    { "role": "assistant", "content": "Hi! How can I help?" }
  ]
}

Response

# Clean response from LLM (passed output guardrail)
{ "allowed": true, "response": "Our return policy is...", "source": "llm" }

# Blocked at input
{ "allowed": false, "response": "Security Alert: Jailbreak attempt detected.", "source": "guardrail" }

# Blocked at output (after retries exhausted)
{ "allowed": false, "response": "Quality Alert: Hallucination detected.", "source": "output_guardrail" }

The source field indicates where the response originated: guardrail | llm | output_guardrail | circuit_breaker | fail_closed (a guard check itself errored — request blocked safe-mode) | system (meta error)

POST /api/upload

Multi-modal file scanning for images, audio, and video. Accepts multipart/form-data. Rate-limited to 10 req/min. Max file size: 10 MB.

Form Fields

Field Type Description
file required file The file to scan
file_type required string "image" | "audio" | "video"

Accepted MIME types: image/png, image/jpeg, image/jpg, audio/wav, audio/x-wav, audio/mpeg, audio/mp3, video/mp4, video/quicktime. The server never trusts the client-declared type alone: the filename extension must agree with file_type, otherwise 415.

# cURL example — image scan
curl -X POST http://localhost:8000/api/upload \
  -H "x-api-key: your-key" \
  -F "file=@screenshot.png" \
  -F "file_type=image"

Response

# Image: blocked (GPS metadata found)
{ "allowed": false, "response": "🛡️ IMAGE BLOCKED: Privacy Risk - GPS Metadata found in image." }

# Audio: allowed (with transcript)
{ "allowed": true, "response": null, "transcript": "Hello, how do I reset my password?", "is_deepfake": false }

# Audio: deepfake detected
{ "allowed": false, "response": "🛡️ AUDIO BLOCKED: Potential AI-Generated/Cloned Voice Detected.", "is_deepfake": true }
GET POST /api/config

Read or update the active guard_config.yaml. Changes are applied immediately via hot-reload — no container restart required.

# Read current config
curl -H "x-api-key: your-key" http://localhost:8000/api/config

# Update config (POST with full YAML as JSON object)
curl -X POST http://localhost:8000/api/config \
  -H "x-api-key: your-key" \
  -H "Content-Type: application/json" \
  -d '{ "global": { "deployment_mode": "passive" }, ... }'

The config endpoint automatically backs up the previous config and rolls back on any validation error.

GET /api/analytics

Returns aggregated threat statistics from the audit log for the past N hours. Works with either credential: x-api-key or Authorization: Bearer <JWT>.

Query Parameters

Param Type Default Description
hours integer 24 Lookback window in hours
# Response
{
  "allowed": 1823,
  "blocked": 47,
  "flagged": 12,
  "total_events": 1882,
  "avg_latency_ms": 38.4,
  "cost_saved_usd": 0.021,
  "threat_types": { "Jailbreak Detection": 18, "PII Redaction": 14, ... },
  "top_offenders": [{ "user": "intern", "violations": 22 }],
  "recent_violations": [...],
  "trend": [{ "time": "2026-02-24 10:00", "allowed": 142, "blocked": 5, "avg_latency_ms": 36.1 }]
}
WS /ws/telemetry

Real-time WebSocket stream broadcasting threat telemetry every 2 seconds to all connected SOC dashboard clients. Data includes live metrics from all 5 threat groups.

// JavaScript example
// Browsers cannot set headers on WebSocket, so auth goes in the query string:
const ws = new WebSocket('ws://localhost:8000/ws/telemetry?api_key=your-key');
// or: ?token= from POST /api/auth/token
ws.onmessage = (event) => {
    const telemetry = JSON.parse(event.data);
    // telemetry.group1 — Prompt & LLM Firewall
    // telemetry.group2 — Model & Data Security
    // telemetry.group3 — Offensive AI Defense
    // telemetry.group4 — AI Supply Chain
    // telemetry.group5 — Physical & Side-Channel
};